生产者消费者模型的C实现(条件变量+互斥锁,信号量)(Linux Ubuntu)

        生产者的工作是制造数据,只有缓冲区没满时,生产者才能把消息放入到缓冲区,否则必须等待; 同时,只有缓冲区不空时,消费者才能从中取出消息,一次消费一段数据(即将其从缓存中移出),否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或者一个消费者从中取出消息,同时只允许一个生产者进行制造,多个生产者不能同时制造,也只允许一个消费之进行消费,多个消费者不能同时进行消费

条件变量+互斥锁实现生产者消费者模型

  • 条件本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。
    • 使用互斥量保护共享数据;
    • 使用条件变量可以使线程阻塞, 等待某个条件的发生, 当条件满足的时候解除阻塞.
  • 条件变量的两个动作:
    • 条件不满足, 阻塞线程
    • 条件满足, 通知阻塞的线程解除阻塞, 开始工作.
  • 条件变量相关函数
    • pthread_cond_t  cond;
      • 作用:定义一个条件变量
    • int pthread_cond_init(pthread_cond_t *restrict cond ,  const pthread_condattr_t *restrict attr);
      • 函数描述:初始化条件变量
      • 函数参数: cond: 条件变量   attr: 条件变量属性, 通常传NULL
  • 函数返回值:成功返回0, 失败返回错误号
  • int pthread_cond_destroy(pthread_cond_t *cond);
    • 函数描述: 销毁条件变量
    • 函数参数: 条件变量
    • 返回值: 成功返回0, 失败返回错误号
  • int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
    • 函数描述: 条件不满足, 引起线程阻塞并解锁;条件满足, 解除线程阻塞, 并加锁
    • 函数参数:
      • cond: 条件变量
      • mutex: 互斥锁变量
  • 函数返回值: 成功返回0, 失败返回错误号
  •  int pthread_cond_signal(pthread_cond_t *cond);
    • 函数描述: 唤醒至少一个阻塞在该条件变量上的线程
    • 函数参数: 条件变量
    • 函数返回值: 成功返回0, 失败返回错误号
  1 //使用条件变量实现生产者和消费者模
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <sys/types.h>
  6 #include <unistd.h>
  7 #include <pthread.h>
  8 typedef struct node
  9 {
 10     int data;
 11     struct node *next;
 12 }NODE;
 13 
 14 NODE *head = NULL;
 15 
 16 //定义一把锁
 17 pthread_mutex_t mutex;
 18 
 19 //定义条件变量
 20 pthread_cond_t cond;
 21 
 22 //生产者线程
 23 void *producer(void *arg)
 24 {
 25     NODE *pNode = NULL;//节点初始化
 26     int n = *(int *)arg;
 27     while(1)
 28     {
 29         //生产一个节点
 30         pNode = (NODE *)malloc(sizeof(NODE));
 31         if(pNode==NULL)
 32         {
 33             perror("malloc error");
 34             exit(-1);
 35         }
 36         pNode->data = rand()%1000;//随机生成0~999的数字作为节点的值
 37         printf("P[%d]:[%d]\n", n, pNode->data);
 38 
 39         //加锁
 40         pthread_mutex_lock(&mutex);
 41 
 42         pNode->next = head;
 43         head = pNode;
 44 
 45         //解锁
 46         pthread_mutex_unlock(&mutex);
 47 
 48         //通知消费者线程解除阻塞
 49         pthread_cond_signal(&cond);
 50 
 51         sleep(rand()%3);
 52     }
 53 }
 54 
 55 
 56 //消费者线程
 57 void *consumer(void *arg)
 58 {
 59     NODE *pNode = NULL;
 60     int n = *(int *)arg;
 61     while(1)
 62     {
 63         //加锁
 64         pthread_mutex_lock(&mutex);
 65 
 66         if(head==NULL)
 67         {
 68             //若条件不满足,需要阻塞等待并解锁
 69             //若条件满足(被生成者线程调用pthread_cond_signal函数通知),解除阻塞并加锁 
 70             pthread_cond_wait(&cond, &mutex);
 71         }
 72 
 73         if(head==NULL)
 74         {
 75             //解锁
 76             pthread_mutex_unlock(&mutex);
 77             continue;
 78         }
 79 
 80         printf("C[%d]:[%d]\n", n, head->data);
 81         pNode = head;
 82         head = head->next;
 83 
 84         //解锁
 85         pthread_mutex_unlock(&mutex);
 86 
 87         free(pNode);
 88         pNode = NULL;
 89 
 90         sleep(rand()%3);
 91     }
 92 }
 93 
 94 int main()
 95 {
 96     int ret;
 97     int i = 0;
 98     pthread_t thread1[5];
 99     pthread_t thread2[5];
100 
101     //初始化互斥锁
102     pthread_mutex_init(&mutex, NULL);
103 
104     //条件变量初始化
105     pthread_cond_init(&cond, NULL);
106 
107     int arr[5];
108     for(i=0; i<5; i++)
109     {
110         arr[i]= i;
111         //创建生产者线程
112         ret = pthread_create(&thread1[i], NULL, producer, &arr[i]);
113         if(ret!=0)
114         {
115             printf("pthread_create error, [%s]\n", strerror(ret));
116             return -1;
117         }
118 
119         //创建消费者线程
120         ret = pthread_create(&thread2[i], NULL, consumer, &arr[i]);
121         if(ret!=0)
122         {
123             printf("pthread_create error, [%s]\n", strerror(ret));
124             return -1;
125         }
126     }
127 
128     //等待线程结束
129     for(i=0; i<5; i++)
130     {
131         pthread_join(thread1[i], NULL);
132         pthread_join(thread2[i], NULL);
133     }
134 
135     //释放互斥锁
136     pthread_mutex_destroy(&mutex);
137 
138     //释放条件变量
139     pthread_cond_destroy(&cond);
140 
141     return 0;
142 }

 执行结果:

信号量实现生产者消费者模型

 

信号量介绍

           信号量相当于多把锁, 可以理解为是加强版的互斥锁

2 相关函数

  • 定义信号量 sem_t sem;//头文件#include <semaphore.h>
  •  int  sem_init(sem_t *sem, int pshared, unsigned int value);   
    • 函数描述: 初始化信号量
    • 函数参数:   sem: 信号量变量 pshared: 0表示线程同步, 1表示进程同步value: 最多有几个线程操作共享数据
    • 函数返回值:成功返回0, 失败返回-1, 并设置errno值
  • int  sem_wait(sem_t *sem);
    • 函数描述: 调用该函数一次, 相当于sem--, 当sem为0的时候, 引起阻塞
    • 函数参数: 信号量变量
    • 函数返回值: 成功返回0, 失败返回-1, 并设置errno值
  • int  sem_post(sem_t *sem);
    • 函数描述: 调用一次, 相当于sem++
    • 函数参数: 信号量变量
    • 函数返回值: 成功返回0, 失败返回-1, 并设置errno值
  • int  sem_trywait(sem_t *sem);
    • 函数描述: 尝试加锁, 若失败直接返回, 不阻塞
    • 函数参数: 信号量变量
    • 函数返回值: 成功返回0, 失败返回-1, 并设置errno值
  • int sem_destroy(sem_t *sem);
    • 函数描述: 销毁信号量
    • 函数参数: 信号量变量
    • 函数返回值: 成功返回0, 失败返回-1, 并设置errno值
  1 //使用信号量实现生产者和消费者模
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <sys/types.h>
  6 #include <unistd.h>
  7 #include <pthread.h>
  8 #include <semaphore.h>
  9 
 10 typedef struct node
 11 {
 12     int data;
 13     struct node *next;
 14 }NODE;
 15 
 16 NODE *head = NULL;
 17 
 18 //定义信号量
 19 sem_t sem_producer;
 20 sem_t sem_consumer;
 21 
 22 //生产者线程
 23 void *producer(void *arg)
 24 {
 25     NODE *pNode = NULL;
 26     while(1)
 27     {
 28         //生产一个节点
 29         pNode = (NODE *)malloc(sizeof(NODE));
 30         if(pNode==NULL)
 31         {
 32             perror("malloc error");
 33             exit(-1);
 34         }
 35         pNode->data = rand()%1000;
 36 
 37         //阻塞
 38         sem_wait(&sem_producer);
 39         pNode->next = head;
 40         head = pNode;
 41 
 42         printf("P[%d]\n", pNode->data);
 43 
 44         //解阻塞给消费者
 45         sem_post(&sem_consumer);
 46 
 47         sleep(rand()%3);
 48     }
 49 }
 52 //消费者线程
 53 void *consumer(void *arg)
 54 {
 55     NODE *pNode = NULL;
 56     while(1)
 57     {
 58 
 61 
 62         printf("C[%d]\n", head->data);
 63         pNode = head;
 64         head = head->next;
 65 
 66         free(pNode);
 67         pNode = NULL;
 68 
 69         //解开阻塞给生产者
 70         sem_post(&sem_producer);
 71 
 72         sleep(rand()%3);
 73     }
 74 }
 75 
 76 int main()
 77 {
 78     int ret;
 79     pthread_t thread1;
 80     pthread_t thread2;
 81 
 82     //初始化信号量
 83     sem_init(&sem_producer, 0, 5);
 84     sem_init(&sem_consumer, 0, 0);
 85 
 86     //创建生产者线程
 87     ret = pthread_create(&thread1, NULL, producer, NULL);
 88     if(ret!=0)
 89     {
 90         printf("pthread_create error, [%s]\n", strerror(ret    ));
 91         return -1;
 92     }
 93 
 94     //创建消费者线程
 95     ret = pthread_create(&thread2, NULL, consumer, NULL);
 96     if(ret!=0)
 97     {
 98         printf("pthread_create error, [%s]\n", strerror(ret    ));
 99         return -1;
100     }
101 
102     //等待线程结束
103     pthread_join(thread1, NULL);
104     pthread_join(thread2, NULL);
105 
106     //释放信号量资源
107     sem_destroy(&sem_producer);
108     sem_destroy(&sem_consumer);
109 
110     return 0;
111 }

 

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux中,可以使用C语言条件变量和线程来实现消费者-生产者模型。下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; int count = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_prod = PTHREAD_COND_INITIALIZER; pthread_cond_t cond_cons = PTHREAD_COND_INITIALIZER; void *producer(void *arg) { int item = 0; while (1) { pthread_mutex_lock(&mutex); // 如果缓冲区已满,则等待消费者消费 while (count == BUFFER_SIZE) { pthread_cond_wait(&cond_prod, &mutex); } buffer[count] = item; count++; printf("Producer produced item %d\n", item); // 唤醒消费者线程 pthread_cond_signal(&cond_cons); pthread_mutex_unlock(&mutex); item++; } pthread_exit(NULL); } void *consumer(void *arg) { while (1) { pthread_mutex_lock(&mutex); // 如果缓冲区为空,则等待生产者生产 while (count == 0) { pthread_cond_wait(&cond_cons, &mutex); } int item = buffer[count - 1]; count--; printf("Consumer consumed item %d\n", item); // 唤醒生产者线程 pthread_cond_signal(&cond_prod); pthread_mutex_unlock(&mutex); } pthread_exit(NULL); } int main() { pthread_t producer_thread, consumer_thread; // 创建生产者和消费者线程 pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); // 等待线程结束 pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); return 0; } ``` 在上面的代码中,生产者线程不断地向缓冲区中生产数据,而消费者线程不断地从缓冲区中消费数据。当缓冲区满时,生产者线程会等待条件变量`cond_prod`,直到有消费者消费数据才会被唤醒。同样,当缓冲区为空时,消费者线程会等待条件变量`cond_cons`,直到有生产者生产数据才会被唤醒。 需要注意的是,在生产者和消费者线程之间共享的变量`count`和`buffer`需要进行互斥访问,因此使用了互斥锁`mutex`来保护共享资源的访问。 希望这个示例能帮助你理解如何在Linux中使用C语言条件变量和线程实现消费者-生产者模型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑化草莓熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值