Windows线程同步的四种方式
在多线程的程序中,很少有多个线程能在其生命期内进行完全独立的操作;通常情况是一些线程进行某些操作,而其他的线程必须对其操作后的结果进行了解。如果不采取同步机制,其他线程会在线程处理任务前访问处理结果,这样会产生错误的了解。例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题;若一个线程负责写操作,其他线程负责读取操作,则不能保证读取的就是修改过的值,这时就必须在变量写操作过程时加上访问限制,在写操作完成后解除访问限制。这种保证线程能正确获取其他线程处理结束后的结果的措施称为线程同步。
线程同步的四种方式:
临界区(Critical Section) :通过对多线程的串行化来访问公共资源或一段代码,本身不是内核对象,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开。临界区被释放后,其他线程才可以抢占。
【初始化临界区】
【删除临界区】
【获取临界区】
【释放临界区】
临界区在使用时,以 CRITICAL_SECTION 结构对象保护共享资源,并分别用 EnterCriticalSection() 和 LeaveCriticalSection() 函数占有和释放一个临界区。所用到的 CRITICAL_SECTION 结构对象必须经过 InitializeCriticalSection() 的初始化后才能使用,而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。
【示例】
互斥量(Mutex) :只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。
【创建互斥量】
【销毁互斥量】
【获取互斥量】
【释放互斥量】
互斥量被某一线程获取时为 non-signaled 状态,释放时进入 signaled 状态。因此,可以利用 WaitForSingleObject 函数验证互斥量是否已分配。互斥量在 WaitForSingleObject 函数返回时自动进入 non-signaled 状态,因为它是“ auto-reset ”模式的内核对象。
【示例】
信号量( Semaphore ) 是维护0到指定最大值之间的同步对象。信号量状态在其计数大于0时是有信号,而其计数是0时是无信号的。信号量对象在控制上可以支持有限数量共享资源的访问。
信号量的特点和用途可用下列几句话定义:
【创建信号量】
【释放信号量】
【打开信号量】
【销毁信号量】
【示例】
事件(Event) :是WIN32提供的最灵活的线程间同步方式,事件可以处于激发状态(signaled or true)或未激发状态(unsignal or false)。根据状态变迁方式的不同,事件可分为两类:
【创建事件】
当第二个参数传入TRUE时将创建manual-reset模式的事件对象,此时即使WaitForSingleObject函数返回也不会回到non-signaled状态。因此,在这种情况下,需要通过如下2个函数明确更改对象状态。
【打开事件】
【复位事件】
【设置事件】
传递事件对象句柄并希望改为non-signed状态时,应调用ResetEvent函数。如果希望改为signaled状态,则可以调用SetEvent函数。
【示例】