用户模式下的线程同步
1、原子访问:一个线程在访问某个资源的同时能够保证没有其他线程在同一时刻访问同一资源
Interlocked系列函数能实现原子访问。Interlocked系列函数能保证对值的修改是以原子方式进行的,且执行的极快,因为他们不需要在用户模式和内核模式之间进行切换
缺点:只能对一个值进行操作,而且从来不会把线程切换到等待状态
2、volatitle关键字告诉编译器不要对这个变量进行任何形式的优化,而是始终从变量在内存中的位置读取变量的值
3、关键段:是指一小段代码独占对一些共享资源的访问权
先定义一个名为g_cs的CRITICAL_SECTION数据结构,然后把任何需要访问共享资源的代码放在EnterCriticalSection(&g_cs)和LeaveCriticalSection(&g_cs)之间
缺点:只能用来对同一个进程中的线程进行同步,且容易陷入死锁,因为无法为进入关键段指定一个最长等待时间
用内核对象进行线程同步
1、线程和进程内核对象在创建时处于未触发状态,终止时处于触发状态。当线程和进程内核对象被触发后,它绝不可能再回到未触发状态
2、除进程、线程外,还有其他内核对象也有触发、未触发两种状态,如事件、信号量、互斥量、可等待的计时器,用于线程同步
3、等待函数:使一个线程自愿进入等待状态,直到指定的内核对象被触发为止
WaitForSingleObject:等待对象被触发返回WAIT_OBJECT_0,等待超时返回WAIT_TIMEOUT,无效参数返回WAIT_FAILED
WaitForMultipleObjects:第三个参数为TRUE时,等待的内核对象全部被触发才返回;为FALSE时,等待的内核对象中有一个被触发就返回(最多等待64个)
4、CreateEvent函数创建事件内核对象,参数bManualReset为TRUE时创建手动重置事件,为FALSE时创建自动重置事件(线程等到自动重置事件对象时,对象会自动重置为未触发状态)
SetEvent函数把事件设置为触发状态,ResetEvent函数把事件变成未触发状态
5、 CreateSemaphore函数创建信号量内核对象,信号量用来对资源进行计数,包含两个成员:最大资源计数和当前资源计数。当前资源计数大于0时信号量处于触发状态,等于0时处于未触发状态。
等待函数发现信号量的当前资源计数为0时,系统会让调用线程进入等待状态;若当前资源计数大于0,那么将计数器减1并让调用线程继续运行。
ReleaseSemaphore函数递增信号量的当前资源计数。
6、互斥量用来确保一个线程独占对一个资源的访问,包含一个使用计数、线程ID和一个递归计数。
互斥量和关键段相同,但其优点是:不同进程中的线程可以访问同一个互斥量;线程在等待对资源的访问权时可以指定一个最长等待时间。
互斥量的线程ID为0,代表该互斥量不为任何线程所占用,处于触发状态;线程ID为非零值时,处于未触发状态。
CreateMutex函数创建互斥量,第二个参数为FALSE时,互斥量处于触发状态,为TRUE时,线程ID被设为调用线程的线程ID,处于未触发状态。
ReleaseMutex函数释放互斥量,将递归计数减1,递归计数为0时,将线程ID设为0,从而触发对象,等待该互斥量的线程即可得到它。