Linux Posix线程条件变量
Posted 庖丁解牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux Posix线程条件变量相关的知识,希望对你有一定的参考价值。
生产者消费者模型 1.多个线程操作全局变量n,需要做成临界区(要加锁--线程锁或者信号量) 2.调用函数pthread_cond_wait(&g_cond,&g_mutex)让这个线程锁在某一个条件上等待 --pthread_cond_wait()函数的本质是①:拿到锁的线程,把锁暂时丢掉(解锁)②:线程休眠,进行等待③:线程等待通知,醒来继续执行(重新获得锁) --这个pthread_cond_wait()函数是一个原子性操作 --注意:丢掉的锁可以被生产线程获得,也可以被消费线程获得,消费者线程获取会陷入等待,生产者线程获得会发送信号,唤醒消费者 3.pthread_cond_signal()生产者拿到锁,生产n,生产完成后,发送信号给消费者(唤醒消费者),生产者离开临界区
//生产者消费者模型 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <pthread.h> //定义线程锁 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义线程条件锁 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //定义全局变量 int g_num = 0; //定义消费者线程数量 #define Consume_Count 2 //定义生产者线程数量 #define Product_Count 4 //消费者线程 void *consume_run(void * arg) { int tnum = (int) arg; while (1) { //因为多线程操作一个全局变量,需要做成临界区,枷锁 pthread_mutex_lock(&mutex); printf("消费者%d进入临界区!\\n", tnum); //因为就算消费者被唤醒,也需要重新检查g_num的值,因为pthread_cond_wait()函数丢锁之后,可能被其他消费者获得 //导致多个消费者线程都执行了pthread_cond_wait()函数陷入等待, //因为多个消费者线程被pthread_cond_signal()唤醒,但是资源只有一个,可能已经被其他消费者使用了 //pthread_cond_wait()也有可能被其他信号唤醒 //所以需要重新判断,而不能使用if while (g_num == 0) { printf("消费者%d开始等待!\\n", tnum); //在该线程锁上,进行条件等待 pthread_cond_wait(&cond, &mutex); printf("消费者%d被唤醒!\\n", tnum); } //表示已经有资源了,可以消费了 printf("消费者%d开始消费!\\n", tnum); g_num--; //解锁 pthread_mutex_unlock(&mutex); sleep(3); } return NULL; } //生产者线程 void *product_run(void * arg) { int tnum = (int) arg; while (1) { //当生产者大于消费者时,可能出现生产过多的商品,需要对商品的上限做一个限制,如果商品过多,需要让生产者睡眠 //涉及到对全局变量的访问,需要加锁 printf("现有资源个数%d!\\n",g_num); pthread_mutex_lock(&mutex); if (g_num > 20) { printf("生产者%d产品已经到达上限,进入睡眠!\\n", tnum); //如果生产产品大于上限,需要睡眠,但是睡眠前应该将锁释放.,留给消费者进行消费 pthread_mutex_unlock(&mutex); sleep(3); continue; } else { printf("生产者%d生产产品!\\n", tnum); //如果生产产品小于上限,那么不需要生产者睡眠,接着生产产品 g_num++; //发送条件信号 printf("生产者%d发送条件信号!\\n", tnum); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); } pthread_mutex_unlock(&mutex); sleep(2); } return NULL; } int main(int arg, char * args[]) { pthread_t thrs[Consume_Count + Product_Count]; int i = 0; for (i = 0; i < Consume_Count; i++) { if (pthread_create(&thrs[i], NULL, consume_run, (void *) i) != 0) { printf("pthread_create() failed !\\n"); return -1; } } for (i = 0; i < Product_Count; i++) { if (pthread_create(&thrs[i + Consume_Count], NULL, product_run, (void *) i) != 0) { printf("pthread_create() failed !\\n"); return -1; } } //join for (i = 0; i < Consume_Count + Product_Count; i++) { if (pthread_join(thrs[i], NULL) != 0) { printf("pthread_join() failed !\\n"); break; } } printf("进程推出了!\\n"); return 0; }
编程遇到的问题
关于生产者消费者模型,生产者加锁通知消费者消费,释放锁,消费者捕捉到信号,wait状态被打断(存在虚假唤醒的情况--很普遍,因此需要用一个锁保护变量加以标识),醒来的消费者拿到锁,但是这个过程不是原子的,意思是假如生产者发信号后,解锁,然后由于某种业务场景,继续获取锁,因为生产者发送信号需要时间,存在一种特殊的情况,生产者发送信号了,后面生产者仍然于消费者wait捕捉信号之前拿到锁,假设存在某种变量是消费者wait之后修改的,而生产者需要加锁判断的,此时会产生问题,生产者判断的变量还没有被消费者所修改,从而引发业务上的错误,我想强调的一点是,生产者发送信号到消费者接收到信号这期间是有延迟的,开发中需要注意到这个问题。
以上是关于Linux Posix线程条件变量的主要内容,如果未能解决你的问题,请参考以下文章
C POSIX 线程的互斥体/条件的工作方式因变量所在的位置而异