下面是一个多线程,生产者消费者问题,一个队列放暂存的数据:
1 #include <iostream> 2 #include <queue> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <pthread.h> 6 7 using std::cout; 8 using std::endl; 9 using std::queue; 10 11 #define N 100 12 #define ST 10 13 14 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 15 pthread_cond_t ready = PTHREAD_COND_INITIALIZER; 16 17 queue<int> que; 18 19 void* threadProducer(void* arg) 20 { 21 while(true) 22 { 23 sleep(rand() % ST); 24 25 cout << "Produce try in...\n"; 26 pthread_mutex_lock(&lock); 27 cout << "Produce in!\n"; 28 int source = rand() % N; 29 cout << "Produce " << source << endl; 30 que.push(source); 31 pthread_mutex_unlock(&lock); 32 cout << "Produce out\n"; 33 34 pthread_cond_signal(&ready); 35 } 36 } 37 38 void* threadConsumer(void* arg) 39 { 40 while(true) 41 { 42 sleep(rand() % ST); 43 44 cout << "Consum try in...\n"; 45 pthread_mutex_lock(&lock); 46 cout << "Consum in!\n"; 47 while(que.empty()) 48 { 49 pthread_cond_wait(&ready, &lock); 50 cout << "Consum from sleep\n"; 51 } 52 cout << "Consum " << que.front() << endl; 53 que.pop(); 54 pthread_mutex_unlock(&lock); 55 cout << "Consum out\n\n"; 56 } 57 } 58 59 int main(void) 60 { 61 pthread_t tProducer, tConsumer; 62 pthread_create(&tProducer, NULL, threadProducer, NULL); 63 pthread_create(&tConsumer, NULL, threadConsumer, NULL); 64 65 pthread_join(tProducer, NULL); 66 pthread_join(tConsumer, NULL); 67 68 exit(0); 69 }
下面是一个多线程的小例子,线程1打印非3的倍数,线程2打印3的倍数:
#include <iostream> #include <stdlib.h> #include <unistd.h> #include <pthread.h> using std::cout; using std::endl; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t ready = PTHREAD_COND_INITIALIZER; int data = 0; void* threadProducer(void* arg) { int i; for(i = 1; i < 22; i++) { sleep(1); if(i % 3 != 0) { cout << "thread1:" << i << endl; } else { pthread_mutex_lock(&lock); data = i; pthread_mutex_unlock(&lock); pthread_cond_signal(&ready); } } } void* threadConsumer(void* arg) { while(true) { pthread_mutex_lock(&lock); while(data == 0) //no data pthread_cond_wait(&ready, &lock); cout <<"thread2:" << data << endl; if(data == 21) break; else data = 0; //empty data pthread_mutex_unlock(&lock); } } int main(void) { pthread_t tProducer, tConsumer; pthread_create(&tProducer, NULL, threadProducer, NULL); pthread_create(&tConsumer, NULL, threadConsumer, NULL); pthread_join(tProducer, NULL); pthread_join(tConsumer, NULL); exit(0); }
程序大致这样:线程1中的循环,如果i不是3的倍数就自己打印了,如果是的话,把这个数放到一个地方(由于这个地方可以被线程2发现,所以要加锁访问),然后唤醒等待数据的线程2(如果线程2还没有在等待,那么这个唤醒则丢失,这是个bug,见下),线程2被唤醒后,消费了这个3的倍数,清空数据区。
上面提到,如果唤醒线程2的消息没有被收到,则bug。看下面的代码,也就多了38一行,让线程2睡了一会,就在它睡觉的那么一会,线程1把3的倍数往那里一扔就走了,自己再继续下两个不是3倍数的数字,这就直接输出了下面两个数字,又到了3倍数,又扔过去覆盖了之前数字:
1 #include <iostream> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <pthread.h> 5 6 using std::cout; 7 using std::endl; 8 9 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 10 pthread_cond_t ready = PTHREAD_COND_INITIALIZER; 11 12 int data = 0; 13 14 void* threadProducer(void* arg) 15 { 16 int i; 17 for(i = 1; i < 22; i++) 18 { 19 sleep(1); 20 21 if(i % 3 != 0) 22 { 23 cout << "thread1:" << i << endl; 24 } 25 else 26 { 27 pthread_mutex_lock(&lock); 28 data = i; 29 pthread_mutex_unlock(&lock); 30 31 pthread_cond_signal(&ready); 32 } 33 } 34 } 35 36 void* threadConsumer(void* arg) 37 { 38 sleep(20); 39 while(true) 40 { 41 pthread_mutex_lock(&lock); 42 while(data == 0) //no data 43 pthread_cond_wait(&ready, &lock); 44 cout <<"thread2:" << data << endl; 45 if(data == 21) 46 break; 47 else 48 data = 0; //empty data 49 pthread_mutex_unlock(&lock); 50 } 51 } 52 53 int main(void) 54 { 55 pthread_t tProducer, tConsumer; 56 pthread_create(&tProducer, NULL, threadProducer, NULL); 57 pthread_create(&tConsumer, NULL, threadConsumer, NULL); 58 59 pthread_join(tProducer, NULL); 60 pthread_join(tConsumer, NULL); 61 62 exit(0); 63 }
从上面可以总结出下面的条件变量的生产者消费者代码模型:
//下面是生产者 pthread_mutex_lock(&lock); //加锁访问临界区 /*在这里生产数据*/ pthread_mutex_unlock(&lock); //解锁 pthread_cond_signal(&ready); //通知消费者 //下面是消费者 pthread_mutex_lock(&lock); //加锁访问临界区 while(没有待消费数据) pthread_cond_wait(&ready, &lock); //睡在这里,等待被唤醒 /*被叫醒了,在这里消费数据*/ pthread_mutex_unlock(&lock); //解锁