对条件变量(condition variable)的讨论(转载)

作者:王东

1.1 什么是条件变量和条件等待?

简单的说: 条件变量(condition variable)是利用线程间共享的全局变量进行同步的一种机制,

主要包括两个动作:一个线程等待某个条件为真,而将自己挂起;另一个线程使的条件成立,并通知等待的线程继续。

为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

Wiki中的定义如下: Conceptually a condition variable is a queue of threads, associated with a monitor, on which a thread may wait for some condition to become true. Thus each condition variable c is associated with an assertion P. While a thread is waiting on a condition variable, that thread is not considered to occupy the monitor, and so other threads may enter the monitor to change the monitor's state. In most types of monitors, these other threads may signal the condition variable c to indicate that assertion P is true in the current state[1].

条件变量(condition variable)是一种特殊的同步变量,它是与一个互斥量(monitor)关联的线程队列,条件变量都与一个断言(assertion) P关联,因为其中的线程队列中有一个线程在等待这个断言P为真。当一个线程处于等待条件变量(condition variable)时,该线程不再占用互斥量(monitor),让其他线程能够进入互斥区去改变条件状态。

 

在条件变量上有两种基本操作:

1. 等待(wait):一个线程因为等待断言(assertion) P为真而处于等待在条件变量上,此时线程不会占用互斥量(monitor); 

2. 通知(signal/notify):另一个线程在使得断言(assertion) P为真的时候,通知条件变量。 一个线程发生signal时,另一个线程被激活,那么两个线程都占用的互斥量(monitor), 选择哪个线程来占用互斥,这就分为了Blocking condition variables(把优先级给被通知的线程)和Nonblocking condition variables(把优先级给发出signal通知的线程[1]。

 

使用条件等待有如下的场景:

多线程访问一个互斥区域内的资源,如果获取资源的条件不够时,则线程需要等待,直到其他线程释放资源后,唤醒等待条件,使得线程得以继续。

例如: Thread1:

          Lock (mutex)

          while (condition is false)

         { //为什么要在这里用while而不是if呢? //参考1.2.1条件变量存在的问题

             Cond_wait(cond, mutex, timeout)

         }

         DoSomething()

         Unlock (mutex)

       

        Thread2:

        Lock (mutex)

        …

       condition is true

       Cond_signal(cond)

       Unlock (mutex)

 

例如

Thread1从一个大小为50的链接池中获取一个链接,如果已经用的链接达到50时,那该线程必须等待一个条件。

Thread2 用完一个链接时,将该链接还给链接池,然后发送条件notify,告诉Thread1 可以继续了。.

 

1.1.1 关于条件变量(condition variable)和信号量(Semaphore)

 

信号量(Semaphore)是一个非负的整数计数器,被用于进程或线程间的同步与互斥。

通过信号量可以实现 “PV操作”这种进程或线程间的同步机制。

P操作是获得资源,将信号量的值减1,如果结果不为负则继续执行,线程获得资源,否则线程被阻塞,处于睡眠状态,直到等待的资源被别的线程释放;

V操作则是释放资源,给信号量的值加1,释放一个因执行P操作而等待的线程。

 

最简单的信号灯形式,信号灯的值只能取0或1,类似于mutex。 当信号量的值为任意非负值(大于1),其值就代表可用资源的个数。

 可以将信号量Semaphore和互斥锁(mutex)来实现一个来实现对一个池的同步和保护。

使用mutex来实现同步,使用semaphore用于实现对资源记数。

 

 获得资源的线程:

   sem_wait (semaphore1)

   Lock (mutex)

   …

   Unlock (mutex)

   sem_post (semaphore2)

 

 释放资源的线程:

   sem_wait (semaphore2)

   Lock (mutex)

   …

   Unlock (mutex)

   sem_post (semaphore1)

 

这个模型很像多线程的生产者与消费者模型,这里的semaphore2是为了防止过度释放。

 

比起信号量来说,条件变量可以实现更为复杂的等待条件。当然,条件变量和互斥锁也可以实现信号量的功能(window下的条件变量只能实现线程同步不能实现进程同步)。

 

在Posix.1基本原理一文声称,有了互斥锁和条件变量还提供信号量的原因是:“本标准提供信号量的而主要目的是提供一种进程间同步的方式;这些进程可能共享也可能不共享内存区。互斥锁和条件变量是作为线程间的同步机制说明的;这些线程总是共享(某个)内存区。这两者都是已广泛使用了多年的同步方式。每组原语都特别适合于特定的问题”。尽管信号量的意图在于进程间同步,互斥锁和条件变量的意图在于线程间同步,但是信号量也可用于线程间,互斥锁和条件变量也可用于进程间。应当根据实际的情况进行决定。

 

信号量最有用的场景是用以指明可用资源的数量[11]。

 

个人的感觉是:由于起源不同,导致了两种理念,一中理念力挺条件变量(condition variable),觉得信号量没有什么用(例如POSIX Thread模型中没有信号量的概念,虽然也提出了Posix Semaphore,但是为什么一开始不把它放在一起呢?);另一理念恰好相反(例如window刚开始没有条件变量的概念,只有信号量的概念)。

 

进化到后来,目前的linux和window都同时具备了这二者。

 

1.2 Linux中的条件等待函数是那些?

 

 Linux提供了的条件等待函数和notify函数。

 

pthread_cond_timedwait(cond, mutex, abstime);

pthread_cond_wait(cond, mutex); 

pthread_cond_signal(cond); //将至少解锁一个线程(阻塞在条件变量上的线程)。

pthread_cond_broadcast(cond) //将对所有阻塞在条件变量上的线程解锁。

 

线程1调用pthread_cond_wait() 所做的事 三个部分:

 

1. 同时对mutex解锁,

2. 并等待条件 cond 发生

3. 获得通知后,对mutex加锁; 调用pthread_cond_wait()后,同时对mutex解锁,并等待条件 cond 发生(要求解锁并阻塞是一个原子操作)现在互斥对象已被解锁,其它线程可以进入互斥区域,修改条件。 此时,pthread_cond_wait() 调用还未返回。

 

等待条件 mycond是一个阻塞操作,这意味着线程将睡眠,在它苏醒之前不会消耗 CPU 周期。直到特定条件发生[3]。

 

 假设另一个线程2对mutex加锁, 并改变条件, 然后调用函数 pthread_cond_signal() 激活等待条件。这意味着线程1现在将苏醒。此时线程1试图对mutex加锁,由于线程2还没有对mutex解锁,所以线程1只有等待,只有在线程2对mutex解锁后,线程1优先获得mutex加锁,然后就能做想做的事情了。 这里是存在问题的:如何让线程1优先获得mutex加锁,而不是其他线程,pthread_mutex_lock 的伪代码[4]中展示了这种实现的可能性,signal函数中优先激活了wait中的线程。

 

 

 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/nhn_devlab/archive/2011/01/05/6117239.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值