Windows核心编程笔记(6)----用户模式下的线程同步
来源:互联网 发布:清梦繁华冢 知乎 编辑:程序博客网 时间:2024/05/15 23:50
1、原子锁
使用InterlockedExchangeAdd函数来实现原子增长,InterlockedExchange\InterlockedExchangePointer用来交换两个变量的值,InterlockedCompareExchange对比数值,相等则交换(对应的InterlockedCompareExchangePointer)。对应的
还有64位函数。
InterlockedIncrement\InterlockedDecrement是比较老的函数,只能增加或递减1,InterlockedExchangeAdd的灵活性更
大。
2、Interlocked 单向链表操作函数(支持原子操作的链表)
InitializeSListHead创建一个空栈InterlockedPushEntrySList入栈
InterlockedPopEntrySList出栈
InterlockedFlushSList清空栈
QueryDepthSList获取栈元素个数
3、高速缓存行
CPU从内存中取出指令时,一次取出高速缓存行大小个字节(32、64、128因CPU型号而异),CPU就不用访问内存总线,直接从缓存中读取指令比内存中读取快多了。
由于多个CPU取出同一块内存数据到各自的高速缓存行,导致内存数据不一致。CPU设计时,当一个CPU修改了它的告诉缓
存行后,其他CPU会收到通知,并使自己的高速缓存行作废。
这意味着,我们应该根据高速缓存行的大小来讲应用程序的数据组织在一起,并将数据与缓存行的边界对齐。这样做的目
的是为了确保不同的CPU能各自访问不同的内存地址,而且这些地址不在同一个高速缓冲行内。
4、使用volatile关键字
volatile告诉编译器,不要对这个变量进行任何形式的优化,而是始终从变量所在内存中的位置读取变量的值。编译器的优化,编译器读取数据到CPU寄存器中,下次需要该数值时直接取寄存器中的值,这样即使变量数值已经改变也
无法知道。使用volatile后,CPU每次都去变量所在内存读取,变量改变后可以及时获取。
5、使用关键段(临界区)CRITICALSECTION
EnterCriticalSection\LeaveCriticalSection,使用前需要初始化InitializeCriticalSection,使用后需要释放DeleteCriticalSection。
关键段优点:易使用,执行速度快;缺点:无法用在多个进程之间对线程进行同步。
同时有两个线程访问资源时,EnterCriticalSection会使一个获得资源,另一个切换到等待状态。如果等待时间太长,
最终回引发异常,超时时间保存在注册表:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\
Session Manager\CriticalSectionTimeout中。默认大约是30天。
可以使用TryEnterCriticalSection来替代EnterCriticalSection,TryEnterCriticalSection会立即返回资源是否正在
被占用。
6、关键段和旋转锁
当一个线程试图进入一个关键段,而这个关键段正在被另一个线程占用时,函数会立即把调用线程切换到等待状态。这意味着线程必须从用户模式切换到内核模式(大约1000个CPU周期),这个开销十分大。为了提高关键段的性能,
Microsoft把旋转锁合并到了关键段中。调用EnterCriticalSection时,会调用一个旋转锁不断循环,尝试获得资源的
访问权。只有在尝试失败后,才会切换进内核状态。为了使用带旋转锁的关键段,需要使用API
InitializeCriticalSectionAndSpinCount来初始化关键段,第二个参数制定循环的次数,如果是在单CPU机器上这个
参数将会被忽略。
SetCriticalSectionSpinCount用来改变旋转锁循环次数。用来保护进程堆的关键段所使用的循环次数大约是4000,这可以作为我们的一个参考值。
EnterCriticalSection在内存不足时会导致异常,但是无返回值;InitializeCriticalSectionAndSpinCount在内存不足时,返回值为FALSE,便于直接测试是否创建成功。
7、Slim读写锁
在Vista以上本版才有此函数,忽略。8、以上几种线程同步方式的性能:
如果希望应用程序得到最佳性能,首先尝试不要共享数据,然后依次使用volatile读取、volatile写入,InterlockedAPI,SRWLock以及关键段。当前仅当这些都不能满足要求时,再使用内核对象(每次都需要在用户模式和内核模式之间
切换,CPU开销十分大)。
9、使用技巧
(1)以原子方式操作一组对象时使用一个锁,缺点是降低了可伸缩性:任何时刻系统只允许一个线程运行。(2)同时访问多个资源时,每个资源都有自己的锁。在获取资源时,所有线程必须以相同顺序来执行。
(3)不要长时间占用锁,其他线程可能进入等待状态,影响程序性能
以下是测试代码:
<span style="white-space:pre"></span>//获取CPU核心数以及每个CPU的高速缓存行的大小
<span style="white-space:pre"></span>PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;DWORD dwLen = 0;while( true ){if ( GetLogicalProcessorInformation(buffer, &dwLen) )break;if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){cout<<"Error code = "<<GetLastError()<<endl;return 1;}if ( buffer )free(buffer);buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(dwLen);if ( NULL == buffer ){cout<<"Error to malloc"<<endl;return 2;}}int nProcCoreCount= 0;int nByteOffset= 0;PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;while( nByteOffset<dwLen ){switch( ptr->Relationship ){case RelationProcessorCore:nProcCoreCount++;break;case RelationCache:cout<<"cpu"<<nProcCoreCount<<"'s cache size is "<<ptr->Cache.LineSize<<"byte"<<endl;break;default:break;}nByteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);ptr++;}cout<<"ProcessorCore count is "<<nProcCoreCount<<endl;free(buffer);
/*////////////////////////////////////////////旋转锁CPU不断比较两个值,会消耗CPU时间。这里假定所有线程都以相同的优先级运行,对于需要用旋转锁的线程,可能需要使用SetProcessPriorityBoost或者SetThreadPriorityBoost函数来禁止线程优先级提升。在只有单处理器上的机器不应该使用旋转锁,否则容易造成死锁。*/DWORDWINAPI Thread1(LPVOID lpParam){while( InterlockedExchange(&g_bUse, TRUE) == TRUE ){//返回TRUE表示正在被使用,继续等待Sleep(0);}//返回FALSE,表示当前没有被使用,我们已经将其设置为正在被使用//do somethingg_nIndex++;Sleep(300);//使用完了后,设置状态为未使用InterlockedExchange(&g_bUse, FALSE);return 0;}
1 0
- Windows核心编程笔记 用户模式下的线程同步
- Windows核心编程笔记(6)----用户模式下的线程同步
- windows 核心编程(用户模式下的线程同步)
- Windows核心编程笔记(八)用户模式下的线程同步
- Windows核心编程笔记(八)用户模式下的线程同步 SRWLock剖析
- Windows核心编程:用户模式下的线程同步
- Windows核心编程:用户模式下的线程同步
- windows核心编程-8.用户模式下的线程同步
- windows核心编程-用户模式下的线程同步1
- windows核心编程用户模式下的线程同步
- windows核心编程---用户模式下的线程同步
- Windows核心编程:(五)用户模式下线程同步
- Windows核心编程学习笔记(17)--用户模式下的线程同步
- 【Windows核心编程学习笔记】用户模式下的线程同步之二---关键段(critical section)
- Windows核心编程(七)用户模式下的线程同步
- Windows核心编程 线程基础 线程调度、优先级、关联性 用户模式下的线程同步
- Windows核心编程学习笔记 第二部分 完成编程任务 第8章 用户模式下的线程同步
- Windows核心编程笔记(7)----内核模式下的线程同步
- Cocos2d-x中 发起http请求
- C语言:内存字节对齐详解[转载]
- UNIX环境C语言编程(5)-系统数据文件
- fatjar地址
- fatjar地址
- Windows核心编程笔记(6)----用户模式下的线程同步
- fatjar地址
- 2015年nefu寒假集训结构体排序专题解题报告
- knowledge_based topic model - AMC
- 踢开Eclisep&Aptana,Emacs变身强大IDE
- 输入一个字符串,统计共有多少个整数并输出。
- fatjar插件地址
- Unity3D游戏开发之背包系统(三)
- 使用Ipython notebook 学习《Python for Data Analysis》 在win7下搭建注意事项