Linux下线程间同步-条件变量 原创 Linux平台 2022年3月31日 16:41 夏至未至 816 当前内容 4068 字,在路上,马上到,马上到 ### 目录 [TOC] ### 何为条件变量 条件变量,当线程在等待满足某些条件时使线程进入睡眠状态,一旦条件满足,就唤醒睡眠的线程。与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直 到某特殊情况发生为止。通常条件变量和互斥锁同时使用。条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步 的一种机制。 ### 条件变量原理 条件的检测是在互斥锁的保护下进行的。线程在改变条件状态之前必须首先锁住互斥量。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量 可以被用来实现这两进程间的线程同步。 ### 条件变量实现 #### 实现流程 1. 初始化:init()或者pthread_cond_tcond=PTHREAD_COND_INITIALIER;属性置为NULL; 2. 等待条件成立:pthread_wait,pthread_timewait.wait()释放锁,并阻塞等待条件变量为真 timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait); 3. 激活条件变量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待线程) 4. 清除条件变量:destroy;无线程等待,否则返回EBUSY清除条件变量:destroy;无线程等待,否则返回EBUSY #### 实现方法 // 初始化条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); // 阻塞等待 int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); // 超时等待 int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex, const timespec *abstime); // 解除所有线程的阻塞 int pthread_cond_destroy(pthread_cond_t *cond); // 至少唤醒一个等待该条件的线程 int pthread_cond_signal(pthread_cond_t *cond); // 唤醒等待该条件的所有线程 int pthread_cond_broadcast(pthread_cond_t *cond); #### 实现代码 条件变量与互斥量配合以实现线程的同步: #include "stdio.h" #include #include #define Num_CONSUMER 2 //消费者数量 #define Num_PRODUCER 2 //生产者数量 #define C_SLEEP 1 //Consumer #define P_SLEEP 1 //producer pthread_t ctid[Num_CONSUMER];//消费者线程 id pthread_t ptid[Num_PRODUCER];//生产者线程 id pthread_cond_t notFull,notEmpty;//缓冲有无东西 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //用于锁住缓冲区 //从 begin 到 end(不含end) 代表产品 //cnt 代表产品数量 //max 代表库房的容量,即最多生产多少产品 int begin = 0,end = 0, cnt = 0, max = 4; void * Consumer(void * pidx) { printf("Consumer thread id %d\n",*((int *)pidx)); while(1) { pthread_mutex_lock(&mutex); while(cnt == 0) {//当缓冲区空时 pthread_cond_wait(&Empty,&mutex); //等待条件成立 } printf("consume %d\n",begin); begin = (begin+1)%max; cnt--; pthread_mutex_unlock(&mutex); sleep(C_SLEEP); pthread_cond_signal(&Full); //相当于条件成立后,发出成立信号的一方 } pthread_exit((void *)0); } void * producer(void * pidx)//producer thread idx { printf("producer thread id %d\n",*((int *)pidx)); while(1) { pthread_mutex_lock(&mutex); while(cnt == max)//当缓冲区满时 { pthread_cond_wait(&Full,&mutex); } printf("produce %d\n",end); end = (end+1)%max; cnt++; pthread_mutex_unlock(&mutex); sleep(P_SLEEP); pthread_cond_signal(&Empty); } pthread_exit((void *)0); } int main() { int i = 0; for(i = 0; i < Num_CONSUMER; i++) { ;int * j = (int *) malloc(sizeof(int)); *j = i; if(pthread_create(&ctid[i],NULL,Consumer,j) != 0) { perror("create Consumer failed\n"); exit(1); } } for(i = 0; i < Num_PRODUCER; i++) { int * j = (int *) malloc(sizeof(int)); *j = i; if(pthread_create(&ptid[i],NULL,producer,j) != 0) { perror("create producer failed\n"); exit(1); } } while(1) { sleep(10); } return 0; } 其中,cond 是 pthread_cond_t 类型的对象,mtx 是pthread_mutex_t类型的对象。pthread_cond_wait 在不同条件下行为不同 1. 当执行 pthread_cond_wait 时,作为一个原子操作包含以下两步: 1) 解锁互斥量 mtx 2) 阻塞进程直到其它线程调用 pthread_cond_signal 以告知 cond 可以不阻塞 2. 当执行 pthread_cond_signal(&cond) 时,作为原子操作包含以下两步: 1) 给 mtx 加锁 2)停止阻塞线程, 因而得以再次执行循环,判断条件是否满足。(注意到此时 mtx 仍然被当前线程独有,保证互斥) 本文标题: Linux下线程间同步-条件变量 本文作者: 夏至未至 发布时间: 2022年3月31日 16:41 最近更新: 2022年3月31日 16:41 原文链接: 许可协议: 署名-非商业性-禁止演绎 4.0 国际(CC BY-NC-ND 4.0) 请按协议转载并保留原文链接及作者 线程间同步(5) 上一个 利用位图(BitMap)查找数据 下一个 Linux下线程间同步-互斥锁 当前文章评论暂未开放,请移步至留言处留言。