生产者消费者模型
线程同步典型的案例即为生产者消费者模型,而借助条件变量来实现这一模型,是比较常见的一种方法。假定有两个线程,一个模拟生产者行为,一个模拟消费者行为。两个线程同时操作一个共享资源,生产者向其中添加产品,消费者从中消费掉产品。
下面展示一些代码片段:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>/*静态初始化*/
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;typedef struct msg{int num;struct msg *next;}Msg,*MSG;MSG head;//创建头节点
//消费者
void *consumer(void *p)
{Msg *mp;while(1){pthread_mutex_lock(&lock);//这里不能为if,因为存在多个消费者的情况while(head == NULL){/*生产者生产的产品,消费完,消费者才调用pthread_cond_wait函数阻塞生产者生产出产品后调用 pthread_cond_signal(&has_product);将阻塞的消费者线程唤醒*/pthread_cond_wait(&has_product,&lock);}/*模拟消费者消费产品 删除一个节点*/mp = head;head = mp->next;pthread_mutex_unlock(&lock);printf("---------consumer %d\n",mp->num);free(mp);//设防节点指针指向的内存空间sleep(rand()%3);}
}
//生产者
void *producer(void *p)
{Msg *mp;while(1){/*生产产品 */mp = (Msg *)malloc(sizeof(Msg));mp->num = rand()%1000+1;mp->next = NULL;printf("---------producer %d\n",mp->num);pthread_mutex_lock(&lock);/* 头插法 将产品插入链表 */ mp->next = head;head = mp;/*这里必须解锁,消费者才会在被条件变量唤醒之后拿到锁执行后续程序,否则即使消费者被signal唤醒,得不到锁pthread_cond_wait函数也不会返回,后续程序就执行不了了*/pthread_mutex_unlock(&lock);/*生产者生产出产品后调用 调用pthread_cond_signal函数将阻塞的消费者线程唤醒*/pthread_cond_signal(&has_product);sleep(rand()%5);}
}
int main(int argc,char *argv[])
{pthread_t pid,cid;int err;srand(time(NULL));err = pthread_create(&pid,NULL,producer,NULL);if(err !=0){printf("%s\n",strerror(err));exit(1);}err = pthread_create(&cid,NULL,consumer,NULL);if(err !=0){printf("%s\n",strerror(err));exit(1);}pthread_join(pid,NULL);pthread_join(cid,NULL);return 0;
}
这里需要注意的有:
在生产者利用互斥锁pthread_mutex_lock(&lock);
对链表进行头插法之后,
pthread_mutex_unlock(&lock)
必须对互斥锁进行解锁,消费者线程才会在被条件变量唤醒之后拿到锁,执行后续程序,否则即使消费者线程被生产者线程调用pthread_cond_signal(&has_product)
唤醒,得不到锁
pthread_cond_wait()
函数就不会返回,后续程序就无法执行。