pthread_cond_wait前面使用while()问题

概念:

  假设实现一个生产者消费者模型,仓库只能装100万件item,生产者每次生产1件,消费者每次消费1件,为了保持数据的同步,那么生产者每次都需要检查仓库是否满了,消费者每次都需要检查仓库是否空了,在加上互斥锁前提下,数据是能得同步保证的。循环的访问且每次都给互斥锁加锁解锁,又称为轮询,如果经常做无用功则线程一直在空转,十分浪费CPU。如果在仓库满了,我们希望生产者停下来等待,同理如果仓库空了,我们希望消费者停下来等待。


互斥锁的初始化:

如果互斥锁是静态分配的,则可以初始化成常值PTHREAD_MUTEX_INITIALIZER,也可以调用pthread_mutex_init函数来初始化

如果互斥锁是动态分配的(例如通过malloc),或者分配在共享内存中,则需要在运行时调用pthread_mutex_init函数来初始化


条件变量初始化:

如果条件变量是静态分配的,则可以初始化成常值PTHREAD_COND_INITIALIZER,也可以调用pthread_cond_init函数来初始化

如果条件变量是动态分配的(例如通过malloc),或者分配在共享内存中,则需要在运行时调用pthread_cond_init函数来初始化


为什么要用while循环而不是if:

  1. while (nready.nready == 0) {  
  2.     Pthread_cond_wait(&nready.cond, &nready.mutex);  
  3. }  
while (nready.nready == 0) {
    Pthread_cond_wait(&nready.cond, &nready.mutex);
}

pthread_cond_signal:点播,通知一个wait线程

pthread_cond_broadcast:广播,通知所有的wait线程

1.假设仓库为空,有2个消费者在等待商品,设为C1和C2

2.假设生产者只生产了1件商品,然后调用pthread_cond_broadcast,则C1和C2都会得到通知

3.假设C1比C2先得到通知,然后加锁把商品消费了,并且解锁,这时C2就能拿到锁,但是此时商品已经没有了,如果此时C2不做检测,则会出现数据同步问题


简单的测试代码:

—– gcc cond_prodcons.c -lpthread —–

  1. #include <pthread.h>  
  2. #include <errno.h>  
  3. #include <stdlib.h>  
  4. #include <stdio.h>  
  5. #include <unistd.h>  
  6.   
  7. #define MAXITEMS 1000000 /* 需要生产n个item */  
  8. #define MAXNTHREADS 10 /* 生产线n条 */  
  9.   
  10. int buff[MAXITEMS];  
  11.   
  12. struct {  
  13.     pthread_mutex_t mutex;  
  14.     int nput;  
  15.     int nval;  
  16. } put = {  
  17.     PTHREAD_MUTEX_INITIALIZER  
  18. };  
  19.   
  20. struct {  
  21.     pthread_mutex_t mutex;  
  22.     pthread_cond_t cond;  
  23.     int nready;  
  24. } nready = {  
  25.     PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER  
  26. };  
  27.   
  28. //创建线程  
  29. int Pthread_create(pthread_t *threadconst pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) {  
  30.     int res = pthread_create(thread, attr, start_routine, arg);  
  31.     if (res != 0) {  
  32.         perror(”pthread_create fail”);  
  33.         exit(EXIT_FAILURE);  
  34.     }     
  35. }  
  36.   
  37. //互斥锁  
  38. int Pthread_mutex_lock(pthread_mutex_t *mutex) {  
  39.     int res = pthread_mutex_lock(mutex);  
  40.     if (res != 0) {  
  41.         perror(”Pthread_mutex_lock fail”);  
  42.     }     
  43. }  
  44.   
  45. //互斥解锁  
  46. int Pthread_mutex_unlock(pthread_mutex_t *mutex) {  
  47.     int res = pthread_mutex_unlock(mutex);  
  48.     if (res != 0) {  
  49.         perror(”Pthread_mutex_unlock fail”);  
  50.     }     
  51. }  
  52.   
  53. //发送线程信号  
  54. int Pthread_cond_signal(pthread_cond_t *cond) {  
  55.     int res = pthread_cond_signal(cond);  
  56.     if (res != 0) {  
  57.         perror(”Pthread_cond_signal fail”);  
  58.     }     
  59. }  
  60.   
  61. /* 
  62. pthread_cond_wait会释放mutex,并进入阻塞状态, 
  63. 一旦获取到信号则会将mutex锁住,并返回 
  64. */  
  65. int Pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {  
  66.     int res = pthread_cond_wait(cond, mutex);  
  67.     if (res != 0) {  
  68.         perror(”pthread_cond_wait fail”);  
  69.     }     
  70. }  
  71.   
  72. //线程函数声明  
  73. void* produce(void*);  
  74. void* consume(void*);  
  75.   
  76. int main(int argc, char const *argv[])  
  77. {  
  78.     int i, count[MAXNTHREADS];  
  79.     pthread_t tid_produce[MAXNTHREADS], tid_consume;  
  80.   
  81.     // n个生产者  
  82.     for (i=0; i<MAXNTHREADS; ++i) {  
  83.         count[i] = 0;  
  84.         Pthread_create(&tid_produce[i], NULL, produce, &count[i]);  
  85.     }  
  86.   
  87.     // 1个消费者,也可以是n个  
  88.     Pthread_create(&tid_consume, NULL, consume, NULL);  
  89.   
  90.     for (i=0; i<MAXNTHREADS; ++i) {  
  91.         pthread_join(tid_produce[i], NULL);  
  92.         printf(”count[%d] = %d\n”, i, count[i]);  
  93.     }  
  94.   
  95.     pthread_join(tid_consume, NULL);  
  96.   
  97.     return 0;  
  98. }  
  99.   
  100. // 生产者  
  101. void* produce(void* arg) {  
  102.       
  103.     int dosignal;  
  104.     for ( ; ; ) {  
  105.         Pthread_mutex_lock(&put.mutex);  
  106.         if (put.nput >= MAXITEMS) {  
  107.             Pthread_mutex_unlock(&put.mutex);  
  108.             return(NULL); /* 数据填满了 */  
  109.         }  
  110.   
  111.         buff[put.nput] = put.nval;  
  112.         put.nput++;  
  113.         put.nval++;  
  114.         Pthread_mutex_unlock(&put.mutex);  
  115.   
  116.         Pthread_mutex_lock(&nready.mutex);  
  117.         dosignal = (nready.nready == 0); /* 是否需要唤醒 */  
  118.         nready.nready++;  
  119.         Pthread_mutex_unlock(&nready.mutex);  
  120.   
  121.         if (dosignal) {  
  122.             Pthread_cond_signal(&nready.cond);  
  123.         }  
  124.   
  125.         *((int *)arg) += 1; /* 当前线程生产了多少个数据 */  
  126.   
  127.     }  
  128.   
  129.     return(NULL);  
  130. }  
  131.   
  132.   
  133. // 消费者  
  134. void* consume(void* arg) {  
  135.   
  136.     int i;  
  137.   
  138.     for (i=0; i<MAXITEMS; i++) {  
  139.   
  140.         Pthread_mutex_lock(&nready.mutex);  
  141.         while (nready.nready == 0) { /* while 循环是防止wait返回时发生虚假唤醒 */  
  142.             Pthread_cond_wait(&nready.cond, &nready.mutex);  
  143.         }  
  144.         nready.nready–;  
  145.         Pthread_mutex_unlock(&nready.mutex);  
  146.   
  147.         //如果线程没同步成功,则会有输出  
  148.         if (buff[i] != i)  
  149.             printf(”buff[%d] = %d\n”, i, buff[i]);  
  150.     }  
  151.   
  152.     return(NULL);  
  153. }  
#include <pthread.h>




#include <errno.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #define MAXITEMS 1000000 /* 需要生产n个item */ #define MAXNTHREADS 10 /* 生产线n条 */ int buff[MAXITEMS]; struct { pthread_mutex_t mutex; int nput; int nval; } put = { PTHREAD_MUTEX_INITIALIZER }; struct { pthread_mutex_t mutex; pthread_cond_t cond; int nready; } nready = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER }; //创建线程 int Pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { int res = pthread_create(thread, attr, start_routine, arg); if (res != 0) { perror("pthread_create fail"); exit(EXIT_FAILURE); } } //互斥锁 int Pthread_mutex_lock(pthread_mutex_t *mutex) { int res = pthread_mutex_lock(mutex); if (res != 0) { perror("Pthread_mutex_lock fail"); } } //互斥解锁 int Pthread_mutex_unlock(pthread_mutex_t *mutex) { int res = pthread_mutex_unlock(mutex); if (res != 0) { perror("Pthread_mutex_unlock fail"); } } //发送线程信号 int Pthread_cond_signal(pthread_cond_t *cond) { int res = pthread_cond_signal(cond); if (res != 0) { perror("Pthread_cond_signal fail"); } } /* pthread_cond_wait会释放mutex,并进入阻塞状态, 一旦获取到信号则会将mutex锁住,并返回 */ int Pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { int res = pthread_cond_wait(cond, mutex); if (res != 0) { perror("pthread_cond_wait fail"); } } //线程函数声明 void* produce(void*); void* consume(void*); int main(int argc, char const *argv[]) { int i, count[MAXNTHREADS]; pthread_t tid_produce[MAXNTHREADS], tid_consume; // n个生产者 for (i=0; i<MAXNTHREADS; ++i) { count[i] = 0; Pthread_create(&tid_produce[i], NULL, produce, &count[i]); } // 1个消费者,也可以是n个 Pthread_create(&tid_consume, NULL, consume, NULL); for (i=0; i<MAXNTHREADS; ++i) { pthread_join(tid_produce[i], NULL); printf("count[%d] = %d\n", i, count[i]); } pthread_join(tid_consume, NULL); return 0; } // 生产者 void* produce(void* arg) { int dosignal; for ( ; ; ) { Pthread_mutex_lock(&put.mutex); if (put.nput >= MAXITEMS) { Pthread_mutex_unlock(&put.mutex); return(NULL); /* 数据填满了 */ } buff[put.nput] = put.nval; put.nput++; put.nval++; Pthread_mutex_unlock(&put.mutex); Pthread_mutex_lock(&nready.mutex); dosignal = (nready.nready == 0); /* 是否需要唤醒 */ nready.nready++; Pthread_mutex_unlock(&nready.mutex); if (dosignal) { Pthread_cond_signal(&nready.cond); } *((int *)arg) += 1; /* 当前线程生产了多少个数据 */ } return(NULL); } // 消费者 void* consume(void* arg) { int i; for (i=0; i<MAXITEMS; i++) { Pthread_mutex_lock(&nready.mutex); while (nready.nready == 0) { /* while 循环是防止wait返回时发生虚假唤醒 */ Pthread_cond_wait(&nready.cond, &nready.mutex); } nready.nready--; Pthread_mutex_unlock(&nready.mutex); //如果线程没同步成功,则会有输出 if (buff[i] != i) printf("buff[%d] = %d\n", i, buff[i]); } return(NULL); }

END


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pthread_cond_broadcast和pthread_cond_wait也是用于线程间同步的函数,类似于pthread_cond_signal和pthread_cond_wait的组合,但有一些区别。 pthread_cond_broadcast用于广播条件变量的信号。当一个线程调用pthread_cond_broadcast时,它会唤醒所有正在等待这个条件变量的线程。这与pthread_cond_signal的区别在于,pthread_cond_signal只会唤醒一个等待线程,而pthread_cond_broadcast会唤醒所有等待线程。 pthread_cond_wait用于等待条件变量的信号,与pthread_cond_signal和pthread_cond_broadcast一起使用。当一个线程调用pthread_cond_wait时,它会阻塞等待条件变量的信号。当收到信号后,线程会重新激活,并且会重新检查条件是否满足。如果条件不满足,线程可能会再次进入等待状态。 以下是一个使用pthread_cond_broadcast和pthread_cond_wait的示例代码: ```c pthread_mutex_t mutex; pthread_cond_t cond; int condition = 0; void* thread1(void* arg) { pthread_mutex_lock(&mutex); while (condition == 0) { pthread_cond_wait(&cond, &mutex); } // 条件满足后执行的代码 pthread_mutex_unlock(&mutex); return NULL; } void* thread2(void* arg) { pthread_mutex_lock(&mutex); condition = 1; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mutex); return NULL; } int main() { pthread_t tid1, tid2; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); pthread_create(&tid1, NULL, thread1, NULL); pthread_create(&tid2, NULL, thread2, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); return 0; } ``` 在上述示例中,thread1线程调用pthread_cond_wait等待条件满足,而thread2线程在某个时刻将条件设置为满足,并调用pthread_cond_broadcast发送信号。这样,所有等待的线程都会被唤醒并执行相应的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值