1、线程之间需要通信的情况:
(1)需要多个线程同时访问一个共享资源,同时不能破坏资源的完整性;
(2)一个线程需要通知其他线程某项任务已经完成;
2、原子递增函数使用Interlocked-开头的函数,在x86系列的cpu,Interlocked函数会在总线上维持一个硬件信号,这个信号会阻止其他CPU访问同一个内存地址。Interlocked函数只占用几个CPU周期(通常小于50),而且不需要在用户模式和内核模式之间切换(这种切换通常需要占用1000个周期以上)。
long g_x = 0;
DWORD WINAPI thread1(VOID* param){
InterlockedExchangeAdd(&g_x,1);// or InterlockedIncrement(&g_x);
return0;
}
DWORD WINAPI thread2(VOID* param){
InterlockedExchangeAdd(&g_x,1);
return0;
}
3、如何利用InterlockedExchange函数实现旋转锁(spinlock)
long g_x = 0;
long g_resource_in_use = FALSE;
DWORD WINAPI thread3(VOID* param){
//waitto access resource
while(InterlockedExchange(&g_resource_in_use, TRUE)==TRUE){
Sleep(0);
}
g_x= 2;
//notaccess resource no longer
InterlockedExchange(&g_resource_in_use,FALSE);
return0;
}
单CUP避免使用旋转锁,因为比较消耗CPU时间,同时阻止其他线程改变锁的值;在多处理器的机器上比较有用,可以切换等待;当多个进程需要对访问一个共享内存(比如内存映射文件)中的值进行同步时,也可以使用Interlocked函数。
4、volatile限定符作用:告诉编译器这个变量可能被应用程序之外的其他东西修改,比如操作系统、硬件或者一个并发执行的线程。确切说,告诉编译器不要对这个变量进行任何形式的优化,而是始终从变量在内存中的位置读取变量的值。
5、使用临界区时候,如果忘记调用EnterCriticalSection和LeaveCriticalSection,即线程强行进入并对资源进行操控,只要有一个线程有这种粗暴的行为,资源就会被破坏。关键段的最大缺点是无法用来在多个进程之间对线程进行同步。
6、读写锁SRWLock,可以允许多个线程同时访问同一个资源,但是只允许一个线程对资源进行修改,使用方法如下:
InitializeSRWLock(&g_wrlock);
//read 共享模式
AcquireSRWLockShared(&g_wrlock);
ReleaseSRWLockShared(&g_wrlock);
//write独占模式
AcquireSRWLockExclusive(&g_wrlock);
ReleaseSRWLockExclusive(&g_wrlock);
虽然SRWLock的性能和关键段差不多,但是还是推荐使用读写锁替代关键段,因为SRWLock不仅更快,而且允许多个线程同时读取,对那些只需要读取共享资源的线程来说,提高了吞吐量和可伸缩性。
7、如果希望在应用程序中得到最近性能,首先应该尝试不要共享数据,然后依次使用volatile读取,volatile写入,Interlocked API,SRWLock以及关键段。当且仅当所有这些都不能满足要求时候,再使用内核对象。
8、以原子方式操作一组对象时使用一个锁;同时访问多个资源注意避免死锁;不要长时间的占用锁,不要在关键段中执行时间很长的函数。