您的位置:首页 > 其它

Windows支持的4种类型的同步对象:临界区、互斥量、事件和信号量

2015-09-01 15:03 507 查看
Windows支持4种类型的同步对象,可以用来同步由并发运行的线程所执行的操作:

临界区
互斥量
事件
信号量

MFC在名为CCriticalSection、CMutex、CEvent和CSemaphore的类中封装了这些对象。下面分别对这些同步对象进行介绍。

临界区

最简单类型的线程同步对象就是临界区。临界区用来串行化对由两个或者多个线程共享的资源的访问。这些线程必须属于相同的进程,因为临界区不能跨越进程的边界工作。

临界区背后的思想就是,每个独占性地访问一个资源的线程可以在访问那个资源之前锁定临界区,访问完成之后解除锁定。如果线程B试图锁定当前线程A锁定的临界区,线程B将阻塞直到该临界区空闲。阻塞时,线程B处在一个十分有效的等待状态,它不消耗处理器时间。

互斥量

Mutex是单词mutually和exclusive的缩写。与临界区一样,互斥量也是用来获得对由两个或者更多线程共享的资源的独占性访问的。与临界区不同的是,互斥量可以用来同步在相同进程或者不同进程上运行的线程。对于进程内线程同步的需要,临界区一般要优于互斥量,因为临界区更快,但是如果希望同步在两个或者多个不同进程上运行的线程,那么互斥量就更合适了。

互斥量和临界区还有另外有一个差别。如果一个线程锁定了临界区而终止时没有解除临界区的锁定,那么等待临界区空闲的其他线程将无限期地阻塞下去。然而,如果锁定互斥量的线程不能在其终止前解除互斥量的锁定,那么系统将认为互斥量被“放弃”了,并自动释放该互斥量,这样等待进程就可以继续进行。

事件

MFC的CEvent类封装了Win32事件对象。一个事件不只是操作系统内核中的一个标记。在任何特定的时间,事件只能处在两种状态中的一种:设置或者重置。设置状态事件也可以认为是处于信号状态,重置状态事件也可以认为是处于非信号状态。CEvent::SetEvent设置一个事件,而CEvent::ResetEvent将事件重置。相关函数CEvent::PulseEvent可以在一次操作中设置和清除一个事件。

有时事件被描述为“线程触发器”。一个线程调用CEvent::Lock在一个事件上阻塞,等待该事件变为设置状态。另一个线程设置事件,从而唤醒该等待线程。设置事件就像按下触发器。它解除等待线程的阻塞并允许该线程继续执行。一个事件可能有一个或者多个在事件上阻塞的线程,如果你的代码正确,那么当该事件变为设置状态时,所有的等待线程都将被唤醒。

Windows支持两种不同类型的事件:自动重置事件手动重置事件。它们之间的差别非常细微,但其意义却是深远的。当在自动重置事件上阻塞的线程被唤醒时,该事件被自动重置为信号状态。手动重置事件不能自动重置,它必须使用编程方式重置。用于选择自动重置事件还是手动重置事件——以及一旦做出选择之后如何使用它们——的规则如下:

1) 如果事件只触发一个线程,那么使用自动重置事件和使用SetEvent唤醒等待线程。这里不需要调用ResetEvent,因为线程被唤醒那一刻事件将自动重置。

2) 如果事件将触发两个或者多个线程,那么使用手动重置线程和使用PulseEvent唤醒所有的等待线程。而且,不需要调用ResetEvent,因为PulseEvent在唤醒线程后将重置事件。

使用手动重置事件来触发多个线程是至关重要的。为什么?因为自动重置事件将在其中一个线程被唤醒的那一刻被重置,因此它只触发一个线程。使用PulseEvent来按下手动重置事件上的触发器也是相当重要的。如果使用SetEvent和ResetEvent,就有保证所有的等待线程都被唤醒。PulseEvent不仅能够设置和重置事件,而且还确保了所有在事件上等待的线程在重置事件之前被唤醒。

与互斥量一样,事件可以用来协调在不同进程上运行的线程,对于跨越进程边界的事件,必须给它指定一个名称。

那么,怎样使用事件来同步线程呢?例如,线程A向缓冲区填充数据,而线程B需要对缓冲区的数据进行处理。假定线程B必须等待来自线程A的一个信号(缓冲区已初始化并准备工作)。这时,自动重置事件是完成这项工作的绝好工具。

自动重置事件适用于触发单线程,但如果与线程B平行的线程对C缓冲的数据进行了完全不同的操作,那会怎么样呢?这就需要手动重置事件一同唤醒线程B和C,因为自动重置事件只能唤醒其中的一个或者另一个,而不能都唤醒 。

再次重申,自动重置事件和CEvent::SetEvent释放在事件上阻塞的单个线程,手动重置事件和CEvent::PulseEvent释放多个线程。

信号量

最后一种同步化对象是信号量。如果任何一个线程锁定了事件、临界区和互斥对象,Lock就会阻塞它们,在这个意义上,这3种对象具有这样的特性:”要么有,要么什么都没有“。信号量则不同,它始终保存有可用资源数量的资源数。锁定信号量会减少资源数,释放信号量则增加资源数。只有在线程试图锁定资源数为0的信号量时,线程才会被阻塞。在这种情况下,直到另一个线程释放信号量,资源数随之增加时,或者直到指定的超时时间期满时,该线程才会被释放。信号量可以用来同步同一进程中的线程,也可以同步不同进程中的线程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: