在windows系统中,系统本身为我们提供了很多锁。通过这些锁的使用,一方面可以加强我们对锁的认识,另外一方面可以提高代码的性能和健壮性。常用的锁以下四种:临界区,互斥量,信号量,event。
(1)临界区
临界区是最简单的一种锁。基本的临界区操作有,
- InitializeCriticalSection
- EnterCriticalSection
- LeaveCriticalSection
- DeleteCriticalSection
如果想要对数据进行互斥操作的话,也很简单,这样做就可以了,
- EnterCriticalSection(/*...*/)
- do_something();
- LeaveCriticalSection(/*...*/)
(2)互斥锁
互斥锁也是一种锁。和临界区不同的是,它可以被不同进程使用,因为它有名字。同时,获取锁和释放锁的线程必须是同一个线程。常用的互斥锁操作有
- CreateMutex
- OpenMutex
- ReleaseMutex
那么,怎么用互斥锁进行数据的访问呢,其实不难。
- WaitForSingleObject(/*...*/);
- do_something();
- ReleaseMutex(/*...*/);
(3)信号量
信号量是使用的最多的一种锁结果,也是最方便的一种锁。围绕着信号量,人们提出了很多数据互斥访问的方案,pv操作就是其中的一种。如果说互斥锁只能对
单个资源进行保护,那么信号量可以对多个资源进行保护。同时信号量在解锁的时候,可以被另外一个thread进行解锁操作。目前,常用的信号量操作有,
- CreateSemaphore
- OpenSemaphore
- ReleaseSemaphore
信号量的使用和互斥锁差不多。关键是信号量在初始化的时候需要明确当前资源的数量和信号量的初始状态是什么,
- WaitForSingleObject(/*...*/);
- do_something();
- ReleaseSemaphore(/*...*/);
(4)event对象
event对象是windows下面很有趣的一种锁结果。从某种意义上说,它和互斥锁很相近,但是又不一样。因为在thread获得锁的使用权之前,常
常需要main线程调用SetEvent设置一把才可以。关键是,在thread结束之前,我们也不清楚当前thread获得event之后执行到哪了。
所以使用起来,要特别小心。常用的event操作有,
- CreateEvent
- OpenEvent
- PulseEvent
- ResetEvent
- SetEvent
我们对event的使用习惯于分成main thread和normal thread使用。main
thread负责event的设置和操作,而normal
thread负责event的等待操作。在CreateEvent的时候,要务必考虑清楚event的初始状态和基本属性。
对于main thread,应该这么做,
- CreateEvent(/*...*/);
- SetEvent(/*...*/);
- WaitForMultiObjects(hThread, /*...*/);
- CloseHandle(/*...*/);
对于normal thread来说,操作比较简单,
- while(1){
- WaitForSingleObject(/*...*/);
- /*...*/
- }
总结:
(1)关于临界区、互斥区、信号量、event在msdn上均有示例代码
(2)一般来说,使用频率上信号量 > 互斥区 > 临界区 > 事件对象
(3)信号量可以实现其他三种锁的功能,学习上应有所侧重
(4)纸上得来终觉浅,多实践才能掌握它们之间的区别