信号量实现生产者和消费者模型
有一块固定容量的缓存区,有多个线程同时访问或操作这个块缓存区,而此时,一个线程称为生产者,生成数据到这块缓存,另一个线程消费者从这个块缓存里读取数据,这个过程就可能引发一系列线程安全问题。而解决问题的关键就是,使消费者和生产者同时只能有一个线程访问这块缓存,也就是说它们之间是互斥的。
方法一:信号量
信号量设置的初始值可以不为1,假设一开始设置信号零的初始值为3;
当第一个线程访问共享资源,那sem的值减一等于2,第二个线程访问共享资源的话在减一等于1,第三个线程访问共享资源在减一等于0,那此时,如果这三个线程都还没有解锁,那么就会阻塞,直到有一个线程解锁信号量加一,下一个线程才可以访问共享资源,这三个访问共享资源的线程是并行访问的,相比于互斥锁而言,提高了效率。
关于信号量的详解点击https://blog.csdn.net/choudan8888/article/details/98518457
方法二:条件变量
当没有可以可消费的食物时,消费者阻塞,等待生产者生产,当生产者生产出产品的时候提醒消费者有东西可以吃了,然后消费者接触阻塞。
关于条件变量的详解点击https://blog.csdn.net/choudan8888/article/details/98474559
代码实现
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<pthread.h>
4 #include<string.h>
5 #include<semaphore.h>
6
7 //定义两个信号量
8 sem_t producer_sem;
9 sem_t customer_sem;
10
11 //定义节点
12 typedef struct Node
13 {
14 int data;
15 struct Node *next;
16 }Node;
17
18 Node *head = NULL;
19 void* producer()
20 {
21 while(1)
22 {
23
23 //一开始,生产者要生产,所以信号量减一
24 sem_wait(&producer_sem); //--
25 Node *p = (Node *)malloc(sizeof(Node));
26 p->data = rand()%1000;
27 p->next = head;
28 head = p;
29 printf("producer = %d\n",head->data);
30 //当生产完成之后,需要提醒消费者可以消费了,也释放自己占用的信号量
31 sem_post(&customer_sem); //++
32 sleep(rand()%3);
33 }
34
35 return NULL;
36 }
37
38 void *customer()
39 {
40 while(1)
41 {
42 //当信号量不是0的时候,消费者就可以访问共享资源,占用一个信号量,信> 号量减一
43 sem_wait(&customer_sem); //--
44
45 Node *p = head->next;
46 printf("customer = %d\n",head->data);
47 free(head);
48 head = p;
49 //用完之后释放解锁,提醒生产者有多余的信号量,
50 sem_post(&producer_sem); //++
51 sleep(rand()%3);
52 }
53 }
54
55
56 int main()
57 {
58 pthread_t p1,p2;
59 //创建两个线程
60 pthread_create(&p1,NULL,producer,NULL);
61 pthread_create(&p2,NULL,customer,NULL);
62
63 //初始化生产者信号量,有四个线程操作共享资源
64 sem_init(&producer_sem,0,4);
65 //初始化消费者信号量,一开始没有资源,所以消费者一开始阻塞
66 sem_init(&customer_sem,0,0);
67
68
69 //释放信号狼
70 sem_destroy(&producer_sem);
71 sem_destroy(&customer_sem);
72
73
74
75 //等待回收线程
76 pthread_join(p1,NULL);
77 pthread_join(p2,NULL);
78
79 return 0;
80 }
条件变量实现生产者和消费者模型
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>
//线程同步需要互斥锁
pthread_mutex_t mutex;
//阻塞线程需要条件变量
pthread_cond_t cond;
typedef struct Node
{
int data;
struct Node *next;
}Node;
Node* head = NULL;
void * producer()
{
while(1)
{
Node *p = (Node *)malloc(sizeof(Node));
p->data = rand()%1000;
//开始枷锁,保护共享资源
pthread_mutex_lock(&mutex);
p->next = head;
head = p;
//开始解锁
printf("producer pthid = %lu,%d\n",pthread_self(),p->data);
pthread_mutex_unlock(&mutex);
//通知阻塞的线程
pthread_cond_signal(&cond);
sleep(rand()%3);
}
return NULL;
}
void * customer()
{
while(1)
{
//枷锁
pthread_mutex_lock(&mutex);
if(head == NULL)
{
//continue;
//在这里做了三件事情阻塞线程,对互斥锁解锁,让生产者那边加锁,生产出东西后返回回来又对互斥锁继续枷锁
pthread_cond_wait(&cond,&mutex);
}
printf("sustomer pthid = %-lu,%d\n",pthread_self(),head->data);
Node*p = head->next;
free (head);
head = p;
//解锁
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
//创建两个线程,一个生产,一个消费
pthread_t p1,p2;
pthread_create(&p1,NULL,producer,NULL);
pthread_create(&p2,NULL,customer,NULL);
//初始化条=条件变量和互斥锁
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
//回收子线程
pthread_join(p1,NULL);
pthread_join(p2,NULL);
//销毁条件变量和互斥锁
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}