windows 核心编程之8 用户模式下的线程同步

来源:互联网 发布:工作计划软件 编辑:程序博客网 时间:2024/06/04 23:50
用户模式下的线程同步

有下面2种情况,需要用到线程同步
1 需要让多个线程同时访问一个资源,同时不能破坏资源的完整性
2 一个线程需要通知另外一个线程,任务完成。


1 原子访问方式:

提供下面以下的原子方式访问的函数:
#include <Windows.h>#include <stdio.h>int main(){// 原子方式操作LONG volatile ivVariable = 10;LONGLONG volatile llVariable = 10;// return initial value of first parameter// you can use it to do subtraction, first parameter negativeLONG ltestVar = InterlockedExchangeAdd(&ivVariable, 1);LONGLONG llTestVariable = InterlockedExchangeAdd64(&llVariable, 2);//BOOL volatile bTest = FALSE;BOOL bOldValue = (BOOL)InterlockedExchange((LONG volatile*)&bTest, TRUE);volatile int*p = new int(10);LONG* lptest = new LONG(100);LONG* plvalue = (LONG*)InterlockedExchangePointer(&p,lptest);delete p;delete lptest;LONG volatile lvolatileCompateValue = 10;// function 参数1与参数3是否相等,不相等不执行操作,//相等时,把参数2赋值给参数1,返回值参数1以前的值LONG lOldValue = InterlockedCompareExchange(&lvolatileCompateValue, 15, 11);// 参数1 是一个指针LONG volatile* lpvolatile = new LONG(11);LONG* lp = new LONG(11);LONG* lOldCompateValue =(LONG*) InterlockedCompareExchangePointer((volatile PVOID*)&lpvolatile,(PVOID)lp,(PVOID)lpvolatile);return 0;}


下面是原子访问的链表栈
#include <Windows.h>#include <stdio.h>#include <tchar.h>// 原子方式访问单向链表typedef struct mydata{int i;TCHAR ch[10];double dou;}LISTDATA;typedef struct _Slist_item{SLIST_ENTRY m_entry;LISTDATA m_data;}LISTTIME,*PLISTTIME;int main(){SLIST_HEADER head;SLIST_ENTRY slistEntry;LISTTIME ltem;PLISTTIME pLitem = NULL;InitializeSListHead(&head);for (int i = 0; i< 10; i++){pLitem = new LISTTIME;pLitem->m_data.i = i;pLitem->m_data.dou = 100;_tcscpy_s(pLitem->m_data.ch,10,TEXT("asdf"));InterlockedPushEntrySList( &head, &pLitem->m_entry );}LONG lSize = QueryDepthSList(&head);for (int i = 0; i < 10; ++i){pLitem = (PLISTTIME)InterlockedPopEntrySList(&head);delete pLitem;}InterlockedFlushSList(&head);return 0;}



2 高速缓存行

Windows SDK 代码最后释放内存有错,buffer指针移动了,下面的代码,已经改好,增加了一些新信息
#include <windows.h>#include <malloc.h>    #include <stdio.h>#include <tchar.h>typedef BOOL (WINAPI *LPFN_GLPI)( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,  PDWORD);int _cdecl _tmain (){BOOL done;BOOL rc;DWORD returnLength;DWORD procCoreCount;DWORD byteOffset;PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer, FreeBuffer;LPFN_GLPI Glpi;Glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")),"GetLogicalProcessorInformation");if (NULL == Glpi) {_tprintf(TEXT("GetLogicalProcessorInformation is not supported.\n"));return (1);}done = FALSE;buffer = NULL;returnLength = 0;while (!done) {rc = Glpi(buffer, &returnLength);if (FALSE == rc) {if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {if (buffer) free(buffer);FreeBuffer = buffer=(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);if (NULL == buffer) {_tprintf(TEXT("Allocation failure\n"));return (2);}} else {_tprintf(TEXT("Error %d\n"), GetLastError());return (3);}} else done = TRUE;}procCoreCount = 0;byteOffset = 0;while (byteOffset < returnLength) {switch (buffer->Relationship) {case RelationProcessorCore:procCoreCount++;break;case RelationNumaNode:printf("节点信息:\n");printf("numaNode = %d\n",buffer->NumaNode.NodeNumber);break;case RelationCache:printf("CPU 高速缓冲区\n");printf("关联性 %d\n",buffer->Cache.Associativity);printf("Cache %d 缓存\n",buffer->Cache.Level);printf("Cache %d 缓存行\n",buffer->Cache.LineSize );printf("Cache %dKB 大小\n", buffer->Cache.Size / 1024);switch(buffer->Cache.Type){case CacheData:printf("CacheData\n");break;case CacheInstruction:printf("CacheInstruction\n");break;case CacheTrace:printf("CacheTrace\n");break;case CacheUnified:printf("CacheUnified\n");break;}break;case RelationProcessorPackage:printf("RelationProcessorPackage:\n");break;default:break;}byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);buffer++;printf("=========================================================\n");}_tprintf(TEXT("Number of active processor cores: %d\n"), procCoreCount);free (FreeBuffer);return 0;}





3 高级线程同步

不要使用旋转锁的方式来,线程之间同步


4 关键段

CRITICAL_SECTION     是关键段的结构体,我们不需要了解结构体的细节,帮助文档也没有它的说明.

下面是初始化关键段得函数,参数是结构体地址

InitializeCriticalSection(&cs);

DeleteCriticalSection(&cs); 这个函数是删除,关键段结构体,必须成对使用,否则资源泄露


EnterCriticalSection(&cs);
//需要保护的资源
LeaveCriticalSection(&cs);

也必须要成对使用

可以使用 TryEnterCriticalSection 来替换 EnterCriticalSection  这个函数会尝试请求资源,如果没有资源,返回false,有资源返回true,同时会更新关键段结构体,所以访问了资源后,可以调用 LeaveCriticalSection。 下面的代码说明情况了。

if(TryEnterCriticalSection(&cs))
{
//需要保护的资源


LeaveCriticalSection(&cs);
}
else
{
//没有资源可以访问
//不需要调用 LeaveCriticalSection;
}

下面的代码介绍了怎么使用关键段

#include <Windows.h>#include <stdio.h>#include <tchar.h>#include <process.h>class MyCriticalSection{public:MyCriticalSection(){InitializeCriticalSection(&m_cs);}~MyCriticalSection(){DeleteCriticalSection(&m_cs);}void Lock(){EnterCriticalSection(&m_cs);}void UnLock(){LeaveCriticalSection(&m_cs);}BOOL TryLock(){return TryEnterCriticalSection(&m_cs);}void TryUnLock(){UnLock();}private:CRITICAL_SECTION m_cs;};int gSum = 0;MyCriticalSection criticalsection;unsigned int WINAPI ThreadFuncOne(LPVOID lparam){criticalsection.Lock();for (int i = 0; i < 100; ++i){gSum++;}criticalsection.UnLock();return 0;}unsigned int WINAPI ThreadFuncTwo(LPVOID lparam){criticalsection.Lock();for (int i = 0; i < 100; ++i){gSum++;Sleep(10);}criticalsection.UnLock();return 0;}unsigned int WINAPI ThreadFuncThree(LPVOID lparam){while(!criticalsection.TryLock()){printf("没有资源可以使用\n");Sleep(10);}printf("资源可以使用\n");for (int i = 0; i < 100; ++i){gSum++;}criticalsection.TryUnLock();return 0;}int main(int argc, char **argv){HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuncOne, NULL, 0, NULL);HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuncTwo, NULL, 0, NULL);HANDLE hThread3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuncThree, NULL, 0, NULL);HANDLE harray[3] = {hThread1,hThread2,hThread3};WaitForMultipleObjects(_countof(harray),harray,TRUE,INFINITE);printf("sum = %d\n", gSum);system("pause");return 0;}

初始化的时候可以使用
//初始化的时候,使用旋转锁 单CPU上没有作用
WINBASEAPI
BOOL
WINAPI
InitializeCriticalSectionAndSpinCount(
    __out LPCRITICAL_SECTION lpCriticalSection,
    __in  DWORD dwSpinCount
    );

SetCriticalSectionSpinCount 设置旋转锁的次数,单CPU没有效果,这个函数是没有使用上面那个函数,初始化关键段,在后期使用中,可以使用下面这个函数,来改变!




原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 工商证没年检怎么办 工行信用卡被锁怎么办 外地卡密码锁了怎么办 营业执照年审过期了怎么办 工商营业执照吊销了怎么办 小规模企业工商年检怎么办 血流变检查偏高怎么办 信誉卡没有邮箱怎么办 税务年报没报怎么办 工商忘记年审了怎么办 营业执照脱审了怎么办 公司年审没有弄怎么办 车检标志丢了怎么办 机动车年检丢了怎么办 汽车保险标志丢了怎么办 车辆年检贴丢失怎么办 车检标贴丢了怎么办 检验标贴丢了怎么办 小车换年检标志怎么办 职称证忘记审验怎么办 联合年报没报怎么办 职称年审过期了怎么办 嘉兴驾模预约怎么办 电大考试去不了怎么办 负债高怎么办房贷 宁波鄞州银行卡怎么办 硕士学位实验数据不好怎么办 小区外过车很吵怎么办 建筑物初级消防证书怎么办 毕业答辩去不了怎么办 卡波西水痘样疹怎么办 58企业认证失败怎么办 炸鸡店没生意怎么办 你好漂亮重名了怎么办 医保卡被冒用怎么办 理财钱被骗走怎么办 个体户怎么办三方协议 社保户籍错了怎么办 身份证号码变更后驾驶证怎么办 公司倒闭欠工资怎么办 海南买房要社保怎么办?