Linux线程唤醒与等待
生产者消费者模式在程序设计中出现频率非常高,经常会有线程间通过消息队列或其他共享变量进行交互的场景。而这时就会出现一个问题,消费者如何知道生产者已经生产了数据呢?有的程序会采取消费者循环判断消息队列大小是否为0,如果不为0则取出数据之类的方法。但是该种方法带来两个问题:
1. 生产者产出数据到消费者获得数据的延时较大。
2. CPU占用较高。
如果需要降低延时,则必然要提高轮询的频率,那么CPU占用就会升高。反之亦然,两者无法同时解决。
于是,唤醒等待机制就成为适合该种场景的解决方案。
该机制需要一个互斥对象以及条件变量共同完成,如下:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;
其中条件变量使用宏结构常量进行赋值。接下来进行互斥对象与条件变量的初始化:
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
生产者唤醒逻辑:
pthread_mutex_lock(&mutex); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex);
消费者等待逻辑:
pthread_mutex_lock(&mutex); pthread_cond_wait(&cond, &mutex); pthread_mutex_unlock(&mutex);
看到这里可能会有点疑问,为何除了条件变量还需要一个互斥对象呢?等待时为什么需要条件变量和互斥对象共同生效呢?
条件变量的操作也需要达到线程安全的要求,因此需要互斥对象来进行保证。避免两个线程同时操作条件变量引发问题。而通过查阅pthread_cond_wait()的相关资料可知,当程序运行到pthread_cond_wait()时,会将互斥对象锁释放,以便生产者能够顺利唤醒。而在消费者被成功唤醒,pthread_cond_wait()等待完成后,互斥对象会被重新上锁直到手动释放。
下方提供完整的DEMO以供参考:
/* test.cpp */ #include <pthread.h> #include <iostream> #include <signal.h> #include <stdlib.h> #include <unistd.h> using namespace std; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex; void *ThreadFunc(void *arg) { pthread_mutex_lock(&mutex); /*此处等待唤醒*/ cout << "Thread sleeping..." << endl; pthread_cond_wait(&cond, &mutex); /*唤醒成功*/ cout << "Thread awakened!" << endl; pthread_mutex_unlock(&mutex); return NULL; } int main(void) { pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); pthread_t tid; pthread_create(&tid, NULL, ThreadFunc, NULL); /*等待5秒再唤醒,方便观察*/ usleep(5000000); pthread_mutex_lock(&mutex); /*唤醒*/ pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); return 0; }
附上操作命令:
g++ test.cpp -o test -pthread ./test
posted on 2019-09-25 16:10 DluT_eDdy 阅读(2565) 评论(0) 编辑 收藏 举报