pthread_cond_signal和pthread_cond_wait简介
来源:互联网 发布:软件开发工程师认证 编辑:程序博客网 时间:2024/05/17 07:10
Linux用于同步的条件变量 pthread_cond_t,一开始学的时候,还是有点难理解的。这里说一下我的理解。
考虑这种情况下的读者写者:写者只往缓冲区写入数据一次,但写的时间不确定。读者负责把这个数据读出来。
利用mutex可以如下面那样实现:
写者和读者共享一个变量isWirte 但其为true时,表示已经写了。为false时,表示写者还没写。
写者:
- //写者在某个不确定的时刻运行下面的代码
- lock(mutex); //上锁
- write(buffer);//往缓冲区写入东西
- isWrite = true; //表示已经写入东西
- unlock(mutex);//解锁
读者:
- //由于读者不知道写者什么时候写了缓冲区,所以采用轮询这样方式
- //进一步,为了不太浪费cpu,将使用sleep函数
- while( !isWrite) //写者还没写入
- {
- sleep(1); //休眠一秒钟
- }
- lock(mutex); //上锁
- read(buffer); //读取缓冲区
- unlock(mutex);
明显这种实现需要轮询,而且实时性差。因为缺少一种通知的机制。如果读者在写者还没写的时候,就进入休眠状态。在写者写完后就通知读者,就可以避免轮询和消除实时性差这个问题。
为此可以设计下面的实现:
写者:
- lock(mutex); //上锁
- write(buffer);//往链表写入东西
- unlock(mutex);//解锁
- signal_to_wakeup(读者)// 发一个信号去通知读者,让读者醒来。
读者:
- lock(mutex);
- if( !isWrite )//写者还没写入
- {
- unlock(mutex); //解锁,让写者可以写
- pause(); //进入睡眠,等待写者唤醒
- }
- //读者已经被写者唤醒
- lock(mutex); //读取临界区,需再次加锁
- read(buffer);
- unlock(mutex);
这个实现还是比较容易理解的。但这个实现有一个竞争条件。如果读者刚执行完if语句里面的unlock(mutex).进行了解锁。还没来得及执行pause失去了cpu。而刚好,写者获得了cpu,并且执行完了上面的那些代码。它确实是发送了一个信号,唤醒读者。但此时的读者并没有进入睡眠状态。当读者再次获取cpu时,它已经错过了那个唤醒信号。所以当它执行pause,进入睡眠后。就长眠不醒了,因为写者不再发送唤醒信号了。
引起这个问题,是因为解锁和进入睡眠这两个操作由两个函数执行,不具有原子性。所以就有了pthread_cond_wait这个系统调用。用来原子地完成这个两个操作。
- pthread_cond_wait
就等同于
- unlock(mutex);//解锁,让写者可以写
- pause(); //进入睡眠,等待写者唤醒
- lock(mutex); //再次锁上,这个不要看漏了
解释到这里,大家应该懂了pthread_cond_wait的工作原理了吧。
同lock需要一个共享的mutex类型变量一样,pthread_cond_wait需要一个共享的pthread_cond_t类型变量。这里设为cond
现在用pthread_cond_wait来重新实现刚才的功能。
写者:
- lock(mutex);
- write(buffer);
- unlock(mutex);
- pthread_cond_signal(cond);
读者:
- lock(mutex);
- pthread_cond_wait(cond,mutex);
- //因为当pthread_cond_wait返回时,mutex又会被锁上,所以不要我们用//lock(mutex)加锁
- read(buffer);
- unlock(mutex);//解锁
pthread_cond_wait也不是太难理解吧。
上面的代码,其实还是有一个缺陷。假如写者先于读者运行,并且运行了pthread_cond_signal(cond); 即发送了唤醒信号。那么将出现刚才说到的问题:当读者执行时,将长眠不醒。即pthread_cond_wait与pthread_cond_signal这两个函数配合使用是有一个缺陷的。
解决的办法是将写者的唤醒信号保存起来,当读者执行时能找到,不会错过。
可以用一个变量来标志写者已经发送了唤醒信号这个动作。比如用一个int变量count。当count等于0时,表示写者还没发送过唤醒信号。大于0时,表示发送过唤醒信号。
实现如下:
其中共享的变量count被初始化为0
写者:
- lock(mutex);
- write(buffer);
- count++;
- unlock(mutex);
- pthread_cond_signal(cond);
读者:
- lock(mutex);
- //假如写者已经发送了信号(即count不为0),那么就不要进入睡眠了。而且此时是加锁状态,可以直接去读缓冲区
- //之所以用while而不是if判断一次,是因为读者进入睡眠的时候,可能会被其他信号打断,而且过早地退出睡眠。由于不是写者唤醒的,故需要再次睡眠
- while( count ==0 ) /
- pthread_cond_wait(cond, mutex);
- //因为当pthread_cond_wait返回时,mutex又会被锁上,所以不要我们lock(mutex)
- read(buffer);
- --count; //复位,可以为下次使用做处理
- unlock(mutex);//解锁
原文:
int x,y;pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_lock(&mut);while (x <= y) {pthread_cond_wait(&cond, &mut);}/* operate on x and y */pthread_mutex_unlock(&mut);
pthread_mutex_lock(&mut);/* modify x and y */if (x > y) pthread_cond_broadcast(&cond);pthread_mutex_unlock(&mut);
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#define BUFFER_SIZE 8struct Products{int buffer[BUFFER_SIZE];/*保证存取操作的原子性 互斥性*/pthread_mutex_t locker;/*是否可读*/pthread_cond_t notEmpty;/*是否可写*/pthread_cond_t notFull;int posReadFrom;int posWriteTo;};int BufferIsFull(struct Products* products){if ((products->posWriteTo + 1) % BUFFER_SIZE == products->posReadFrom){return (1);}return (0);}int BufferIsEmpty(struct Products* products){if (products->posWriteTo == products->posReadFrom){return (1);}return (0);}/*制造产品*/。void Produce(struct Products* products, int item){/*原子操作*/pthread_mutex_lock(&products->locker);/*无空间可写入*/while (BufferIsFull(products)){pthread_cond_wait(&products->notFull, &products->locker);}/*写入数据*/products->buffer[products->posWriteTo] = item;products->posWriteTo++;if (products->posWriteTo >= BUFFER_SIZE)products->posWriteTo = 0;/*发信*/pthread_cond_signal(&products->notEmpty);/*解锁*/pthread_mutex_unlock(&products->locker);}int Consume(struct Products* products){int item;pthread_mutex_lock(&products->locker);/*为空时持续等待,无数据可读*/while (BufferIsEmpty(products)){pthread_cond_wait(&products->notEmpty, &products->locker);}/*提取数据*/item = products->buffer[products->posReadFrom];products->posReadFrom++;/*如果到末尾,从头读取*/if (products->posReadFrom >= BUFFER_SIZE)products->posReadFrom = 0;pthread_cond_signal(&products->notFull);pthread_mutex_unlock(&products->locker);return item;}#define END_FLAG (-1)struct Products products;void* ProducerThread(void* data){int i;for (i = 0; i < 16; ++i){printf("producer: %d\n", i);Produce(&products, i);}Produce(&products, END_FLAG);return NULL;}void* ConsumerThread(void* data){int item;while (1){item = Consume(&products);if (END_FLAG == item)break;printf("consumer: %d\n", item);}return (NULL);}int main(int argc, char* argv[]){pthread_t producer;pthread_t consumer;int result;pthread_create(&producer, NULL, &ProducerThread, NULL);pthread_create(&consumer, NULL, &ConsumerThread, NULL);pthread_join(producer, (void *)&result);pthread_join(consumer, (void *)&result);exit(EXIT_SUCCESS);}
#include <pthread.h>#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>pthread_mutex_t mymutex1 = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_t mymutex2 = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;void *mythread1(void *param){printf("begin mythread1.\n");pthread_mutex_lock(&mymutex1);printf("wait in mythread1.\n");pthread_cond_wait(&mycond,&mymutex1);pthread_mutex_unlock(&mymutex1);printf("end mythread1.\n");return NULL;}void *mythread2(void *param){printf("begin mythread2.\n");pthread_mutex_lock(&mymutex2);printf("wait in mythread2.\n");pthread_cond_wait(&mycond,&mymutex2);pthread_mutex_unlock(&mymutex2);printf("end mythread2.\n");return NULL;}int main(void){printf("begin main thread.\n");int i;pthread_t tid1,tid2;pthread_create(&tid1,NULL,mythread1,NULL);pthread_create(&tid2,NULL,mythread2,NULL);sleep(5);printf("try to wake up mythread1 and mythread2 in main thread.\n");if(pthread_cond_broadcast(&mycond)){printf("error\n");return 1;}void *res;pthread_join(tid1, &res);pthread_join(tid2, &res);printf("end main thread.\n");return 0;}
- #include <pthread.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- pthread_mutex_t mymutex1 = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_t mymutex2 = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
- void *mythread1(void *param)
- {
- printf("begin mythread1.\n");
- pthread_mutex_lock(&mymutex1);
- printf("wait in mythread1.\n");
- pthread_cond_wait(&mycond,&mymutex1);
- pthread_mutex_unlock(&mymutex1);
- printf("end mythread1.\n");
- return NULL;
- }
- void *mythread2(void *param)
- {
- printf("begin mythread2.\n");
- pthread_mutex_lock(&mymutex2);
- printf("wait in mythread2.\n");
- pthread_cond_wait(&mycond,&mymutex2);
- pthread_mutex_unlock(&mymutex2);
- printf("end mythread2.\n");
- return NULL;
- }
- int main(void)
- {
- printf("begin main thread.\n");
- int i;
- pthread_t tid1,tid2;
- pthread_create(&tid1,NULL,mythread1,NULL);
- pthread_create(&tid2,NULL,mythread2,NULL);
- sleep(2);
- printf("try to wake up mythread1 and mythread2 in main thread.\n");
- if(pthread_cond_broadcast(&mycond)){
- printf("error\n");
- return 1;
- }
- void *res;
- pthread_join(tid1, &res);
- pthread_join(tid2, &res);
- printf("end main thread.\n");
- return 0;
- }
begin mythread1.
wait in mythread1.
begin mythread2.
wait in mythread2.
end mythread2.
try to wake up mythread1 and mythread2 in main thread.
end mythread1.
end main thread.
- #include <pthread.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- pthread_mutex_t mymutex1 = PTHREAD_MUTEX_INITIALIZER;
- //pthread_mutex_t mymutex2 = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
- void *mythread1(void *param)
- {
- printf("begin mythread1.\n");
- pthread_mutex_lock(&mymutex1);
- printf("wait in mythread1.\n");
- pthread_cond_wait(&mycond,&mymutex1);
- pthread_mutex_unlock(&mymutex1);
- printf("end mythread1.\n");
- return NULL;
- }
- void *mythread2(void *param)
- {
- printf("begin mythread2.\n");
- pthread_mutex_lock(&mymutex1);
- printf("wait in mythread2.\n");
- pthread_cond_wait(&mycond,&mymutex1);
- pthread_mutex_unlock(&mymutex1);
- printf("end mythread2.\n");
- return NULL;
- }
- int main(void)
- {
- printf("begin main thread.\n");
- int i;
- pthread_t tid1,tid2;
- pthread_create(&tid1,NULL,mythread1,NULL);
- pthread_create(&tid2,NULL,mythread2,NULL);
- sleep(2);
- printf("try to wake up mythread1 and mythread2 in main thread.\n");
- if(pthread_cond_broadcast(&mycond)){
- printf("error\n");
- return 1;
- }
- void *res;
- pthread_join(tid1, &res);
- pthread_join(tid2, &res);
- printf("end main thread.\n");
- return 0;
- }
$ gcc threadTest.c -o test.exe
123@xyy ~/gcc-test
$ ./test.exe
begin main thread.
begin mythread1.
wait in mythread1.
begin mythread2.
wait in mythread2.
try to wake up mythread1 and mythread2 in main thread.
end mythread1.
end mythread1.
end main thread.
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- pthread_cond_signal和pthread_cond_wait简介
- IOS视频播放器开发系列(二)——前期尝试或探索
- readers and writers problem 读者写者问题 写者优先 C++实现
- final 关键字
- java基础面试题2
- 跟我一起写 Makefile(四) 转自http://blog.csdn.net/haoel/article/details/2889
- pthread_cond_signal和pthread_cond_wait简介
- ./configure详解
- 充值系列——充值系统安全问题(四)
- Android动画fillAfter和fillBefore
- mmap
- 跟我一起写 Makefile(五) 转自http://blog.csdn.net/haoel/article/details/2890
- vc GetMessage函数不能退出进程问题
- 哈希表
- 思科的 H.264 编码器 OpenH264