如果生产者将容器填满,需要通知消费者,
如果消费者将容器清空,需要通知生产者。
(我个人觉得如果有多个生产者和消费者,就排成队列,通知第一个就行。不知道实际情况是什么样子的)

/*
生产者消费者模型(简单版)
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
struct Node
{int num;struct Node*next;
};//头节点
struct Node*head = NULL;void *producer(void*arg){//不断的创建新的节点,添加到链表中while (1){struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->next = head;head = newNode;newNode->num = rand()%1000;printf("add node, num : %d,tid : %ld.\n",newNode->num,pthread_self());usleep(100);}return NULL;
}
void *customer(void*arg){while (1){//保存头节点的指针struct Node*tmp = head;head = head->next;printf("del node,num : %d,tid : %ld.\n",tmp->num,pthread_self());free(tmp);usleep(100);}return NULL;
}
int main(void){pthread_t ptids[5],ctids[5];for(int i = 0;i < 5;i++){pthread_create(&ptids[i],NULL,producer,NULL);pthread_create(&ctids[i],NULL,customer,NULL);}for(int i = 0;i < 5;i++){pthread_detach(ptids[i]);pthread_detach(ctids[i]);}pthread_exit(NULL);return 0;
}

简单的运行的结果
解决方法:
1)互斥量
2)条件变量,实现线程的通信

如何生成 core 文件?
1、首先查看并更改 core 文件的大小设置


2、在生成的可执行文件中加入可调式信息
在生成了core 文件后,打开 gdb

3、通过使用 core-file (core filename)来打开 core 文件,查看 core 文件当中的内容。

总的来说,上面的程序存在两个问题:1)一个是多个进程操作同一个数据但是没有同步的问题
2)另一个是当 head 为null 的时候会被 costumer 访问 head-> next 的问题。

解决第一个问题:加上互斥量

在这里插入代码片

会发生死锁

解决第二个问题,加上条件变量,生产者生产完成后唤醒消费者,消费者在没有物品的时候等待。

但是依然会死锁,因为没有释放互斥量

/*条件变量的类型 pthread_cond_tint pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);int pthread_cond_destroy(pthread_cond_t *cond);int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);- 等待,调用了该函数,线程会阻塞int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);- 等待多长时间,调用了这个函数,线程会阻塞,直到指定的时间阻塞int pthread_cond_signal(pthread_cond_t *cond);- 唤醒一个或者多个等待的线程int pthread_cond_broadcast(pthread_cond_t *cond);- 唤醒所有的等待的线程
*/#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
//创建一个互斥量
pthread_mutex_t mutex;
//创建条件变量
pthread_cond_t cond;struct Node
{int num;struct Node*next;
};//头节点
struct Node*head = NULL;void *producer(void*arg){//不断的创建新的节点,添加到链表中while (1){pthread_mutex_lock(&mutex);struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->next = head;head = newNode;newNode->num = rand()%1000;printf("add node, num : %d,tid : %ld.\n",newNode->num,pthread_self());//只要生产了一个就通知消费者消费pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);usleep(100);}return NULL;
}
void *customer(void*arg){while (1){//保存头节点的指针pthread_mutex_lock(&mutex);struct Node*tmp = head;//判断是否有数据if(head != NULL){head = head->next;printf("del node,num : %d,tid : %ld.\n",tmp->num,pthread_self());free(tmp);pthread_mutex_unlock(&mutex);usleep(100);}else{//没有数据,需要等待pthread_cond_wait(&cond,&mutex);//当wait 函数对这个线程进行阻塞的时候,会对这个线程进行解锁,线程不阻塞的时候,会把mutex 互斥量加上去。//这样就不至于产生影响。pthread_mutex_unlock(&mutex);//  pthread_mutex_unlock(&mutex);}}return NULL;
}
int main(void){pthread_t ptids[5],ctids[5];pthread_mutex_init(&mutex,NULL);pthread_cond_init(&cond,NULL);for(int i = 0;i < 5;i++){pthread_create(&ptids[i],NULL,producer,NULL);pthread_create(&ctids[i],NULL,customer,NULL);}for(int i = 0;i < 5;i++){pthread_detach(ptids[i]);pthread_detach(ctids[i]);}while (1){sleep(100);}//不加 while 死循环会直接执行下面销毁互斥量的语句,那互斥量就没法用了pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);pthread_exit(NULL);// pthread_mutex_destroy(&mutex);//不能放这里,放这里直接退出了就无法执行了return 0;
}


使用信号量

/*信号量的类型 sem_tint sem_init(sem_t *sem, int pshared, unsigned int value);- 初始化信号量- 参数- sem : 信号变量的地址- pshared : 0 用在线程间,非0 用在进程间- value : 信号量中的值int sem_destroy(sem_t *sem);- 释放资源int sem_wait(sem_t *sem);- 对信号量加锁,调用一次对信号量的值减一,如果为0就阻塞。int sem_trywait(sem_t *sem);int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);int sem_post(sem_t *sem);- 对信号量解锁,调用一次对信号量减一int sem_getvalue(sem_t *sem, int *sval);sem_t psem;sem_t csem;init(psem, 0, 8);init(csem, 0, 0);producer() {sem_wait(&psem);sem_post(&csem)}customer() {sem_wait(&csem);sem_post(&psem)}*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<semaphore.h>
//创建一个互斥量
pthread_mutex_t mutex;
sem_t psem;
sem_t csem;struct Node
{int num;struct Node*next;
};//头节点
struct Node*head = NULL;void *producer(void*arg){//不断的创建新的节点,添加到链表中while (1){sem_wait(&psem);pthread_mutex_lock(&mutex);struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->next = head;head = newNode;newNode->num = rand()%1000;printf("add node, num : %d,tid : %ld.\n",newNode->num,pthread_self());pthread_mutex_unlock(&mutex);sem_post(&csem);usleep(100);}return NULL;
}
void *customer(void*arg){while (1){//保存头节点的指针sem_wait(&csem);pthread_mutex_lock(&mutex);struct Node*tmp = head;//判断是否有数据head = head->next;printf("del node,num : %d,tid : %ld.\n",tmp->num,pthread_self());free(tmp);pthread_mutex_unlock(&mutex);sem_post(&psem);}return NULL;
}
int main(void){pthread_t ptids[5],ctids[5];pthread_mutex_init(&mutex,NULL);sem_init(&psem,0,8); //表示容器空位sem_init(&csem,0,0);//表示生产的物品数for(int i = 0;i < 5;i++){pthread_create(&ptids[i],NULL,producer,NULL);pthread_create(&ctids[i],NULL,customer,NULL);}for(int i = 0;i < 5;i++){pthread_detach(ptids[i]);pthread_detach(ctids[i]);}while (1){sleep(100);}//不加 while 死循环会直接执行下面销毁互斥量的语句,那互斥量就没法用了pthread_mutex_destroy(&mutex);pthread_exit(NULL);// pthread_mutex_destroy(&mutex);//不能放这里,放这里直接退出了就无法执行了return 0;
}

运行结果非常丝滑

2022-2-3 牛客C++项目 —— 生产者消费者模型(条件变量、信号量)相关推荐

  1. Golang并发——并发技术Goroutine和channel的使用、定时器、生产者消费者、条件变量、select

    Goroutine: goroutine是Go并行设计的核心.goroutine说到底其实就是协程,它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些gor ...

  2. linux知识(二)互斥量、信号量和生产者消费者模型

    linux知识(二)互斥量.信号量和生产者消费者模型 一.互斥量 产生原因 二.信号量 生产者消费者模型 一.互斥量 产生原因 使用多线程常常会碰到数据混乱的问题,那么使用互斥量,相当于"加 ...

  3. Linux 多线程编程(实现生产者消费者模型)

    Linux 多线程编程 线程分类 线程按照其调度者可以分为用户级线程和内核级线程两种. 内核级线程 在一个系统上实现线程模型的方式有好几种,因内核和用户空间提供的支持而有一定程度的级别差异.最简单的模 ...

  4. 仿牛客论坛项目(下)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(上) 仿牛客论坛项目 15.kafka 1.阻塞队列 2.Kafka入门 简介 术语解释 下载 配置 ...

  5. 仿牛客论坛项目(3)

    仿牛客论坛项目 一.阻塞队列 1.1 测试 二.kafka入门 2.1 kafka下载 2.2 测试 三.Spring整合kafka 3.1 引入依赖 3.2 修改配置文件 3.3 测试 四.发布系统 ...

  6. 仿牛客社区项目笔记-帖子模块(核心)

    仿牛客社区项目笔记-帖子模块(核心) 1. 帖子模块 1.1 过滤敏感词 1.2 发布帖子 1.3 帖子详情 1.4 显示评论 1.5 添加评论 1.6 私信列表 1.7 发送私信 1. 帖子模块 分 ...

  7. 云服务器上部署仿牛客网项目

    云服务器上部署仿牛客网项目 安装JRE 安装Maven 安装MySQL 给mysql导入数据 安装Redis 安装kafka 安装ElasticSearch Wkhtmltopdf 安装tomcat ...

  8. 仿牛客社区项目(第一章)

    文章目录 第一章:初始 SpringBoot,开发社区首页 仿牛客社区项目开发首页功能 一. 实体引入 1. User类 2. DiscussPost 类 3. Page类 二. 配置文件 三. da ...

  9. 仿牛客论坛项目(上)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(下) 仿牛客论坛项目上 1. Spring 在测试类中使用Spring环境 @Primary的作用 @ ...

最新文章

  1. 【C++自我精讲】基础系列二 const
  2. python画正方形-用Python Turtle画一个正方形
  3. 监控j服务器jvm运行情况 - spring boot jvisualvm
  4. [Android]ListView控件之Adapter性能优化
  5. Microsoft RTF栈溢出漏洞(CVE-2010-3333)漏洞分析
  6. C语言高级技巧-在Makefile中引用你的头文件
  7. Java线程面试题 Top 50
  8. 硬件知识:串口通讯的起始、数据、停止位是怎么分配的?
  9. 真香系列-JSFinder实用改造
  10. 海南省重点公共场所WiFi覆盖率达到97.7%
  11. 机器学习-西瓜书、南瓜书第五章
  12. 将 Android* x86 NDK 供 Eclipse* 而移植 NDK 演示示例应用程序
  13. Windows10键盘快捷键大全
  14. 大数据hadoop讲解
  15. Gravity:环形二维码扫描识别传感器详细介绍和工作原理
  16. Java-springboot生鲜电商项目(一)数据设计与项目初始化
  17. 免费云服务器+免费虚拟主机推荐
  18. Hive设置连接用户名和密码
  19. 前端企业微信开发内嵌H5记录
  20. 【转贴】[原创]V刹安装调整体会

热门文章

  1. GITHUB设置代理——解决git clone下载过慢的问题
  2. android shape大小,Android shape属性详解
  3. 太阳能光伏发电整流逆变实训装置,QY-TF01
  4. 创建压缩文件时,Keka总是询问每一次文件名的解决方法
  5. The Top 100 Masterpieces of Classical Music 古典音乐100首经典杰作
  6. 从华为云到米家APP,智能家居行业如何突破发展?智能家居未来发展方向(下)
  7. Ubuntu远程拷贝SCP问题
  8. 让程序在崩溃时体面的退出之总结
  9. oracle 视图 自增列,Oracle实现自增列
  10. ICLR2021放榜~6篇SOTA GNN论文推荐