linux 生产者消费者模型 信号量(灯) 条件变量

生产者消费者模型:

模型对象:1.生产者(1或多个)   2.消费者(1或多个)   3.容器(商品)     

复制代码
 1 /*
 2     生产者和消费者模型(粗略版本)
 3     生产者未生产 消费者开始消费 发生错误
 4 */
 5 #include <stdio.h>
 6 #include <pthread.h>
 7 #include <unistd.h>
 8 #include <stdlib.h>
 9 //链表
10 struct Node
11 {
12     int num;//数据
13     struct Node * next;//保存下一个结点
14 };
15 //头结点
16 struct Node * head = NULL;
17 //生产者
18 void * producer(void * arg)
19 {
20     //不断创建新的结点,添加到链表中
21     while(1)
22     {
23         struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型
24         newNode->next = head;//新结点指向头结点
25         head = newNode;//头节点更新   头插法
26         newNode->num = rand() % 1000;
27         printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self());
28         usleep(100);
29     }
30     return NULL;
31 }
32 //消费者
33 void * customer(void * arg)
34 {
35     while(1)
36     {
37         //保存头节点的指针
38         struct Node * tmp = head;
39         head = head->next;
40         printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self());
41         free(tmp);//释放结点空间
42         usleep(100);
43     }
44     return NULL;
45 }
46 int main()
47 {
48     //创建5个生产者线程 和 5个消费者线程 容器:链表
49     pthread_t ptids[5],ctids[5];
50     for(int i = 0; i < 5; i++)
51     {
52         pthread_create(&ptids[i], NULL, producer, NULL);
53         pthread_create(&ctids[i], NULL, customer, NULL);
54     }
55     //线程分离
56     for(int i = 0; i < 5; i++)
57     {
58         pthread_detach(ptids[i]);
59         pthread_detach(ctids[i]);
60     }
61     pthread_exit(NULL);//线程退出   不执行return 0; 子线程不受影响继续执行
62     return 0;
63 }
复制代码

使用互斥量解决 段错误 问题,但效率低:

复制代码
 1 #include <stdio.h>
 2 #include <pthread.h>
 3 #include <unistd.h>
 4 #include <stdlib.h>
 5 //创建一个互斥量
 6 pthread_mutex_t mutex;
 7 //链表
 8 struct Node
 9 {
10     int num;//数据
11     struct Node * next;//保存下一个结点
12 };
13 //头结点
14 struct Node * head = NULL;
15 //生产者
16 void * producer(void * arg)
17 {
18     //不断创建新的结点,添加到链表中
19     while(1)
20     {
21         pthread_mutex_lock(&mutex);
22         struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型
23         newNode->next = head;//新结点指向头结点
24         head = newNode;//头节点更新   头插法
25         newNode->num = rand() % 1000;
26         printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self());
27         pthread_mutex_unlock(&mutex);
28         usleep(100);
29     }
30     return NULL;
31 }
32 //消费者
33 void * customer(void * arg)
34 {
35     while(1)
36     {
37         pthread_mutex_lock(&mutex);
38         //保存头节点的指针
39         struct Node * tmp = head;
40         if(head != NULL)
41         {
42             //有数据
43             head = head->next;
44             printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self());
45             free(tmp);//释放
46             pthread_mutex_unlock(&mutex);
47             usleep(100);
48         }
49         else
50         {
51             //没有数据 也要解锁 否则会退出循环重复加锁 导致死锁
52             pthread_mutex_unlock(&mutex);
53         }
54     }
55     return NULL;
56 }
57 int main()
58 {
59     //初始化互斥量
60     pthread_mutex_init(&mutex,NULL);
61     //创建5个生产者线程 和 5个消费者线程 容器:链表
62     pthread_t ptids[5],ctids[5];
63     for(int i = 0; i < 5; i++)
64     {
65         pthread_create(&ptids[i], NULL, producer, NULL);
66         pthread_create(&ctids[i], NULL, customer, NULL);
67     }
68     //线程分离
69     for(int i = 0; i < 5; i++)
70     {
71         pthread_detach(ptids[i]);
72         pthread_detach(ctids[i]);
73     }
74     while(1)
75     {
76         sleep(10);//如果没有while循环 会结束互斥量 
77     }
78     pthread_mutex_destroy(&mutex);
79     pthread_exit(NULL);//线程退出   不执行return 0; 子线程不受影响继续执行
80     return 0;
81 }
复制代码

条件变量(引起阻塞,解除阻塞): 配合互斥量使用   (例如没有商品,消费者可以通知生产者生产商品) 

复制代码
  1 /*
  2     条件变量的类型 pthread_cond_t
  3     int pthread_cond_init(pthread_cond_t * restrict cond, const pthread_condattr_t * restrict attr);
  4     int pthread_cond_destroy(pthread_cond_t * cond);
  5     int pthread_cond_wait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex);
  6         - 等待, 调用了该函数, 线程会阻塞
  7     int pthread_cond_timedwait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex, const struct timespec * restrict abstime);
  8         - 等待多长时间, 调用了这个函数,线程会阻塞,直到指定时间结束
  9     int pthread_cond_signal(pthread_cond_t * cond);
 10         - 唤醒一个或者多个等待的线程
 11     int pthread_cond_broadcast(pthread_cond_t * cond);
 12         - 唤醒所有的等待的线程
 13 */
 14 #include <stdio.h>
 15 #include <pthread.h>
 16 #include <unistd.h>
 17 #include <stdlib.h>
 18 //创建一个互斥量
 19 pthread_mutex_t mutex;
 20 //创建条件变量
 21 pthread_cond_t cond;
 22 //链表
 23 struct Node
 24 {
 25     int num;//数据
 26     struct Node * next;//保存下一个结点
 27 };
 28 //头结点
 29 struct Node * head = NULL;
 30 //生产者
 31 void * producer(void * arg)
 32 {
 33     //不断创建新的结点,添加到链表中
 34     while(1)
 35     {
 36         pthread_mutex_lock(&mutex);
 37         struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型
 38         newNode->next = head;//新结点指向头结点
 39         head = newNode;//头节点更新   头插法
 40         newNode->num = rand() % 1000;
 41         printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self());
 42         //只要生产了一个,就通知消费者
 43         pthread_cond_signal(&cond);
 44         pthread_mutex_unlock(&mutex);
 45         usleep(100);
 46     }
 47     return NULL;
 48 }
 49 //消费者
 50 void * customer(void * arg)
 51 {
 52     while(1)
 53     {
 54         pthread_mutex_lock(&mutex);
 55         //保存头节点的指针
 56         struct Node * tmp = head;
 57         //判断是否有数据
 58         if(head != NULL)
 59         {
 60             //有数据
 61             head = head->next;
 62             printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self());
 63             free(tmp);//释放
 64             pthread_mutex_unlock(&mutex);
 65             usleep(100);
 66         }
 67         else
 68         {
 69             //没有数据, 需要等待
 70             //当这个函数调用阻塞的时候,会对互斥锁进行解锁, 当不阻塞的时候,继续向下指向, 会重新加锁
 71             pthread_cond_wait(&cond, &mutex);//没有商品 传递cond 等待+解锁 有商品生产了 cond变化 重新运行 加锁 下条语句解锁
 72             pthread_mutex_unlock(&mutex);
 73         }
 74     }
 75     return NULL;
 76 }
 77 int main()
 78 {
 79     //初始化互斥量
 80     pthread_mutex_init(&mutex,NULL);
 81     //初始化条件变量
 82     pthread_cond_init(&cond,NULL);
 83     //创建5个生产者线程 和 5个消费者线程 容器:链表
 84     pthread_t ptids[5],ctids[5];
 85     for(int i = 0; i < 5; i++)
 86     {
 87         pthread_create(&ptids[i], NULL, producer, NULL);
 88         pthread_create(&ctids[i], NULL, customer, NULL);
 89     }
 90     //线程分离
 91     for(int i = 0; i < 5; i++)
 92     {
 93         pthread_detach(ptids[i]);
 94         pthread_detach(ctids[i]);
 95     }
 96     while(1)
 97     {
 98         sleep(10);//如果没有while循环 会结束互斥量 
 99     }
100     pthread_mutex_destroy(&mutex);
101     pthread_cond_destroy(&cond);
102     pthread_exit(NULL);//线程退出   不执行return 0; 子线程不受影响继续执行
103     return 0;
104 }
复制代码

信号量(灯):用于阻塞线程(灯亮表明资源可用,灯灭表明资源不可用)(不能保证线程数据安全,配合互斥锁使用) 

复制代码
  1 /*
  2     信号量: semaphore
  3     信号量的类型 sem_t
  4     int sem_init(sem_t * sem, int pshared, unsigned int value);
  5         - 初始化信号量
  6         - 参数
  7             - sem: 信号量变量的地址
  8             - pshared: 0:用在线程间,  非0:用在进程间
  9             - value: 信号量中的值
 10     int sem_destroy(sem_t * sem);
 11         - 释放资源
 12     int sem_wait(sem_t * sem);
 13         - 对信号加锁 ,调用一次对信号量的值 -1, 如果值为0, 就阻塞
 14     int sem_trywait(sem_t * sem);
 15     int sem_timedwait(sem_t * sem, const struct timespec * abs_timeout);
 16     int sem_post(sem_t * sem);
 17         - 解锁一个信号量,调用一次对信号量的值 +1
 18     int sem_getvalue(sem_t * sem, int * sval);
 19 
 20     sem_t psem;
 21     sem_t csem;
 22     init(psem, 0, 8); //8是初始量 生产者的限制值 生产调用减少同时产生商品 消费调用增加同时消费商品
 23     init(csem, 0, 0); //消费者为0
 24     producer()
 25     {
 26         sem_wait(&psem);//调用 -1    
 27         sem_post(&csem);// +1
 28     }
 29     customer()
 30     {
 31         sem_wait(&csem);
 32         sem_post(&psem);
 33     }
 34 */
 35 #include <stdio.h>
 36 #include <pthread.h>
 37 #include <unistd.h>
 38 #include <stdlib.h>
 39 #include <semaphore.h>
 40 //创建一个互斥量
 41 pthread_mutex_t mutex;
 42 //创建两个信号量
 43 sem_t psem;//生产者信号量
 44 sem_t csem;//消费者信号量
 45 //链表
 46 struct Node
 47 {
 48     int num;//数据
 49     struct Node * next;//保存下一个结点
 50 };
 51 //头结点
 52 struct Node * head = NULL;
 53 //生产者
 54 void * producer(void * arg)
 55 {
 56     //不断创建新的结点,添加到链表中
 57     while(1)
 58     {
 59         sem_wait(&psem);//初始量为8,  psem - 1
 60         pthread_mutex_lock(&mutex);
 61         struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型
 62         newNode->next = head;//新结点指向头结点
 63         head = newNode;//头节点更新   头插法
 64         newNode->num = rand() % 1000;
 65         printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self());
 66         pthread_mutex_unlock(&mutex);
 67         sem_post(&csem);//csem + 1
 68         usleep(100);
 69     }
 70     return NULL;
 71 }
 72 //消费者
 73 void * customer(void * arg)
 74 {
 75     while(1)
 76     {
 77         sem_wait(&csem);//csem - 1
 78         pthread_mutex_lock(&mutex);
 79         //保存头节点的指针
 80         struct Node * tmp = head;
 81         head = head->next;
 82         printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self());
 83         free(tmp);//释放
 84         pthread_mutex_unlock(&mutex);
 85         sem_post(&psem);//psem + 1
 86         usleep(100);
 87     }
 88     return NULL;
 89 }
 90 int main()
 91 {
 92     //初始化互斥量
 93     pthread_mutex_init(&mutex,NULL);
 94     //初始化信号量
 95     sem_init(&psem, 0, 8);
 96     sem_init(&csem, 0, 0);
 97     //创建5个生产者线程 和 5个消费者线程 容器:链表
 98     pthread_t ptids[5],ctids[5];
 99     for(int i = 0; i < 5; i++)
100     {
101         pthread_create(&ptids[i], NULL, producer, NULL);
102         pthread_create(&ctids[i], NULL, customer, NULL);
103     }
104     //线程分离
105     for(int i = 0; i < 5; i++)
106     {
107         pthread_detach(ptids[i]);
108         pthread_detach(ctids[i]);
109     }
110     while(1)
111     {
112         sleep(10);//如果没有while循环 会结束互斥量 
113     }
114     pthread_mutex_destroy(&mutex);
115     pthread_exit(NULL);//线程退出   不执行return 0; 子线程不受影响继续执行
116     return 0;
117 }
复制代码

posted on   廿陆  阅读(31)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示