头图

线程间同步之消费者与生产者案例(Condition Variable)

该程序通过一个生产者-消费者的例子来展示线程间的同步情况,具体方式为生产者生产一个结构体串在链表的表头上,消费者从表头取走结构体,生产者未生产或生产的已经被拿完,则消费者需要挂起等待.

本文通过两种链表方式来进行实现,注意是在linux环境下编译链接:
1、生产者和消费者访问链表的顺序是LIFO的。

  1 #include <stdlib.h>
  2 #include <pthread.h>
  3 #include <stdio.h>
  4 
  5 struct msg {
  6     struct msg *next;
  7     int num;
  8 };
  9 
 10 struct msg *head;
 11 pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
 12 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 13 
 14 void *consumer(void *p)
 15 {   
 16     struct msg *mp;
 17     
 18     for (;;) {
 19         pthread_mutex_lock(&lock);
 20         while (head == NULL)
 21             pthread_cond_wait(&has_product, &lock);
 22         mp = head;
 23         head = mp->next;
 24         pthread_mutex_unlock(&lock);
 25         printf("Consume %d\n", mp->num);
 26         free(mp);
 27         sleep(rand() % 5);
 28     }
 29 }
 30 
 31 void *producer(void *p)
 32 {
 33     struct msg *mp;
 34     for (;;) {
 35         mp = malloc(sizeof(struct msg));
 36         mp->num = rand() % 1000 + 1;
 37         printf("Produce %d\n", mp->num);
 38         pthread_mutex_lock(&lock);
 39         mp->next = head;
 40         head = mp;
 41         pthread_mutex_unlock(&lock);
 42         pthread_cond_signal(&has_product);
 43         sleep(rand() % 5);
 44     }
 45 }
 46 

2、生产者和消费者访问链表的顺序是FIFO的。

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<pthread.h>
  4 #include<unistd.h>
  5 /* 程序演示了一个生产者-消费者的例子,生产者生产一个结构体串在链表的表头上,消费者
  6  * 从表尾取走结构体。注意: 不一定产生一次就取走一次,虽然产生一次就唤醒一次消费者
  7  * 但有可能此时并未调度消费者线程运行,但取走的一定是表尾的结构体,即最快生产剩下未被取走的即FIFO */
  8 struct msg
  9 {   
 10     struct msg *next;
 11     int num;
 12 };
 13 
 14 struct msg *head;
 15 pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
 16 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 17 
 18 void *consumer(void *p)
 19 {
 20     struct msg *mp;
 21     for (;;)
 22     {
 23         pthread_mutex_lock(&lock);
 24         struct msg *t = NULL;
 25         while (head == NULL){
 26             pthread_cond_wait(&has_product, &lock);//直到producer生产处至少一个mp,才会唤醒此处等待的以has_pr    oduct为Condition Variable的消费者线程
 27         }
 28         if (head->next != NULL)
 29         {
 30                 mp = head;
 31                 t = head;
 32                 while(mp->next !=NULL)
 33                 {
 34                         mp = mp->next;
 35                 }
 36                 while(t->next != mp){
 37                         t = t->next;
 38                 }
 39                 t->next = mp->next;
 40         }
 41         else
 42         {
 43             mp = head;
 44             head = mp->next;
 45         }
 46         pthread_mutex_unlock(&lock);
 47         printf("Consume %d\n", mp->num);
 48         free(mp);
 49         sleep(rand() % 5);
 50     }
 51 }
 52 
 53 void *producer(void *p)
 54 {
 55     struct msg *mp;
 56     for (;;)
 57     {
 58         mp = malloc(sizeof(struct msg));
 59         mp->num = rand() % 1000 + 1;
 60         printf("Produce %d \n", mp->num);
 61         pthread_mutex_lock(&lock);
 62         mp->next = head;
 63         head = mp;
 64         pthread_mutex_unlock(&lock);
 65         pthread_cond_signal(&has_product);//唤醒以has_product为条件变量的wait中的一个线程
 66         sleep(rand() % 5);
 67     }
 68 }
 69 
 70 int main(int argc, char *argv[])
 71 {
 72     pthread_t pid, cid;
 73     srand(time(NULL));
 74     pthread_create(&pid, NULL, producer, NULL);
 75     pthread_create(&cid, NULL, consumer, NULL);
 76     pthread_join(pid, NULL);
 77     pthread_join(cid, NULL);
 78     return 0;
 79 }

在linux下的编译链接运行命令如下:
gcc sourcecode.c -o sourcecode -lpthread

FIFO(先生产先取用)方式执行结果如下图:
image.png

C++初学者

9 声望
0 粉丝
0 条评论
推荐阅读
vscode 配置json文件记录
众所周知vscode的json文件配置比较麻烦,推荐整理配置好的一套json用来减轻后面配环境的折磨。编译器使用的是MinGW64(clang和llvm一直没搞定),可以实现运行后弹出独立的黑框终端!生成的目标文件统一到一个文件...

沐小轲阅读 692

C 程序眼中的 Unicode
去年写了一篇文章「在 C 程序中处理 UTF-8 字符串」,介绍了如何使用 GLib 提供的 UTF-8 字符串处理函数来实现基本的 UTF-8 文本处理。不过,GLib 是一个功能比较全面的 C 程序库,C 字符串处理仅仅是它的一个很...

garfileo3阅读 5.8k评论 5

滚蛋吧,正则表达式!
你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」,首先想到的就是直接百度上搜索一个,然后采用 CV 大法神奇地接入到你的代码中?

良许3阅读 1.4k

程序员适合创业吗?
大家好,我是良许。从去年 12 月开始,我已经在视频号、抖音等主流视频平台上连续更新视频到现在,并得到了不错的评价。每个视频都花了很多时间精力用心制作,欢迎大家关注哦~考虑到有些小伙伴没有看过我的视频,...

良许3阅读 1.2k

计算机如何表示整数
在计算机中,任何的数据都是用二进制: 0 和 1 来表示。整数也不例外。生活中的 10,在 8 个字节的整数中表示为 00001010。但是这样子只能表示正数和零。怎么表示负数呢?于是有了符号位的概念。在 8 个字节的整...

kang2阅读 3.2k评论 7

C语言获取服务器mac地址
它的信息保存在结构体struct ifconf中,有可能不止一个。获取到的信息保存在ifc_buf中。第二个逻辑就是根据网卡的名字去获取mac地址,主要用下面的函数完成:

禹鼎侯阅读 3.3k

比cat更好用的命令!
但 cat 命令两个很重大的缺陷:1. 不能语法高亮输出;2. 文本太长的话无法翻页输出。正是这两个不足,使得 cat 只能用来查看行数不多的小文件。

良许2阅读 610

C++初学者

9 声望
0 粉丝
宣传栏