本来打算用一个形象的生活情况来比喻条件互斥的,但想了再想实在没有想到比较科学贴切的比喻.
那还是开门见山来说吧.
Condition Variable无论在C/C++还是C#,JAVA语言里,都会搭配一个Mutex来用.
我们知道Mutex的普通意义上是维持一个互斥变量,从而保证一个或一组操作的原子性.
同样,简单的说Mutex加在Condition Variable上也是为了保证它的原子性了.
Condition Variable,有条件的唤醒机制.最经典不过的就是生产--消息者模型了.
但有一个细节,消费者需要有"产品"才能继续它的消费行为,因此当消费者发现"产品"
被消费完了?它该怎么办?
没错,普通情况下它就会进入等待挂起状态.但这一状态什么时候才能结束?又是谁来告诉它
有"产品"可消费呢?没错,这个时候消费者就是在等待"有产品可消费"这一条件才会苏醒.
这个时候我们就能用到Condition Variable了.
上代码:#include <stdio.h>
#include <stdlib.h> #include <pthread.h> struct msg{ struct msg *next; int num; }; struct msg *head; pthread_cond_t has_product;//Condition Variable pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//互斥锁初始化 void *consumer(void *p) { struct msg *mp; for(;;){ pthread_mutex_lock(&lock);//保证生产与消费的互斥,消费者取得lock while(head == NULL) pthread_cond_wait(&has_product,&lock);
//其实while这一过程并不是必需的, pthread_cond_wait这一过程已经可以实现等待-执行可程了.但由于线程被唤醒的情况有多种,我们需要的是head!=NULL这种情况才会继续执行.而且pthread_cond_wait()这个方法还会有一个内在的执行过程,在pthread_cond_wait()这一过程中我们必需保证lock的持有,当线程刷新了等待队列之后,在被持起之前lock会被释放.
当另一个线程调用pthread_cond_signal()唤醒之前需要先把lock给释放了,因为调用pthread_cond_signal()后,消费进程需要重新通过pthread_cond_wait()这个方法获得lock,然后执行逻辑处理代码,最后消费进程释放lock.
mp = head; head = mp->next; pthread_mutex_unlock(&lock);//释放lock printf("Consumer %d\n",mp->num); free(mp); sleep(rand()%5); } } void *producer(void *p) { struct msg *mp; for(;;){ mp = malloc(sizeof(struct msg)); mp->num = rand() % 1000+1; printf("Produce %d\n",mp->num); pthread_mutex_lock(&lock);//为保证操作的原子性获得lock mp->next = head; head = mp; pthread_mutex_unlock(&lock);//释放lock pthread_cond_signal(&has_product);//唤醒消费进程 sleep(rand()%5); } } int main(int argc,char *argv[]) { pthread_t pid,cid; srand(time(NULL)); cid = pthread_create(&cid,NULL,consumer,NULL); pid = pthread_create(&pid,NULL,producer,NULL); sleep(5); pthread_join(pid,NULL); pthread_join(cid,NULL); return 0; }
上面文字解释是关键部份,主要是pthread_cond_wait()这一内在执行过程比较重要.