windows 核心编程之8 用户模式下的线程同步
2013-08-15 12:13
309 查看
用户模式下的线程同步
有下面2种情况,需要用到线程同步
1 需要让多个线程同时访问一个资源,同时不能破坏资源的完整性
2 一个线程需要通知另外一个线程,任务完成。
1 原子访问方式:
提供下面以下的原子方式访问的函数:
下面是原子访问的链表栈
2 高速缓存行
Windows SDK 代码最后释放内存有错,buffer指针移动了,下面的代码,已经改好,增加了一些新信息
3 高级线程同步
不要使用旋转锁的方式来,线程之间同步
4 关键段
CRITICAL_SECTION 是关键段的结构体,我们不需要了解结构体的细节,帮助文档也没有它的说明.
下面是初始化关键段得函数,参数是结构体地址
InitializeCriticalSection(&cs);
DeleteCriticalSection(&cs); 这个函数是删除,关键段结构体,必须成对使用,否则资源泄露
EnterCriticalSection(&cs);
//需要保护的资源
LeaveCriticalSection(&cs);
也必须要成对使用
可以使用 TryEnterCriticalSection 来替换 EnterCriticalSection 这个函数会尝试请求资源,如果没有资源,返回false,有资源返回true,同时会更新关键段结构体,所以访问了资源后,可以调用 LeaveCriticalSection。 下面的代码说明情况了。
if(TryEnterCriticalSection(&cs))
{
//需要保护的资源
LeaveCriticalSection(&cs);
}
else
{
//没有资源可以访问
//不需要调用 LeaveCriticalSection;
}
下面的代码介绍了怎么使用关键段
初始化的时候可以使用
//初始化的时候,使用旋转锁 单CPU上没有作用
WINBASEAPI
BOOL
WINAPI
InitializeCriticalSectionAndSpinCount(
__out LPCRITICAL_SECTION lpCriticalSection,
__in DWORD dwSpinCount
);
SetCriticalSectionSpinCount 设置旋转锁的次数,单CPU没有效果,这个函数是没有使用上面那个函数,初始化关键段,在后期使用中,可以使用下面这个函数,来改变!
有下面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 negative LONG 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没有效果,这个函数是没有使用上面那个函数,初始化关键段,在后期使用中,可以使用下面这个函数,来改变!
相关文章推荐
- Windows核心编程学习七:用户模式下的线程同步
- windows核心编程-8.用户模式下的线程同步
- windows 核心编程(用户模式下的线程同步)
- 核心编程笔记8——用户模式下的线程同步
- 《Windows via C/C++》学习笔记(四)用户模式的“线程同步”
- Windows核心编程学习笔记 第二部分 完成编程任务 第8章 用户模式下的线程同步
- Windows Via C/C++:用户模式下的线程同步——原子操作:Interlocked函数族
- windows线程同步-原子操作-Interlocked系列函数(用户模式)
- windows编程之内核模式下的线程同步
- Windows via C/C++ 学习(16)用户模式下的线程同步(一)
- 基于Visual C++之Windows核心编程代码分析(2)实现Windows用户管理
- windows-用户模式下的线程同步(整理)
- Windows用户模式下的线程同步之CRITICAL_SECTION(关键字)
- 《Windows via C/C++》学习笔记 —— 用户模式的“线程同步”之“读写锁”
- 《Windows via C/C++》学习笔记 —— 用户模式的“线程同步”之“关键代码段”
- Windows Via C/C++:用户模式下的线程同步——概述
- Windows Via C/C++:用户模式下的线程同步——原子操作:Interlocked函数族
- 《Windows via C/C++》学习笔记 —— 用户模式的“线程同步”之“互锁函数族”
- CLR via C# 读书笔记 4-1 线程同步-常见的锁,原生用户模式和核心模式 (上)
- Windows Via C/C++:用户模式下的线程同步——轻量级读写锁(Slim Reader-Writer Locks)