2022-2-3 牛客C++项目 —— 生产者消费者模型(条件变量、信号量)
如果生产者将容器填满,需要通知消费者,
如果消费者将容器清空,需要通知生产者。
(我个人觉得如果有多个生产者和消费者,就排成队列,通知第一个就行。不知道实际情况是什么样子的)
/*
生产者消费者模型(简单版)
*/
#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++项目 —— 生产者消费者模型(条件变量、信号量)相关推荐
- Golang并发——并发技术Goroutine和channel的使用、定时器、生产者消费者、条件变量、select
Goroutine: goroutine是Go并行设计的核心.goroutine说到底其实就是协程,它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些gor ...
- linux知识(二)互斥量、信号量和生产者消费者模型
linux知识(二)互斥量.信号量和生产者消费者模型 一.互斥量 产生原因 二.信号量 生产者消费者模型 一.互斥量 产生原因 使用多线程常常会碰到数据混乱的问题,那么使用互斥量,相当于"加 ...
- Linux 多线程编程(实现生产者消费者模型)
Linux 多线程编程 线程分类 线程按照其调度者可以分为用户级线程和内核级线程两种. 内核级线程 在一个系统上实现线程模型的方式有好几种,因内核和用户空间提供的支持而有一定程度的级别差异.最简单的模 ...
- 仿牛客论坛项目(下)
代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(上) 仿牛客论坛项目 15.kafka 1.阻塞队列 2.Kafka入门 简介 术语解释 下载 配置 ...
- 仿牛客论坛项目(3)
仿牛客论坛项目 一.阻塞队列 1.1 测试 二.kafka入门 2.1 kafka下载 2.2 测试 三.Spring整合kafka 3.1 引入依赖 3.2 修改配置文件 3.3 测试 四.发布系统 ...
- 仿牛客社区项目笔记-帖子模块(核心)
仿牛客社区项目笔记-帖子模块(核心) 1. 帖子模块 1.1 过滤敏感词 1.2 发布帖子 1.3 帖子详情 1.4 显示评论 1.5 添加评论 1.6 私信列表 1.7 发送私信 1. 帖子模块 分 ...
- 云服务器上部署仿牛客网项目
云服务器上部署仿牛客网项目 安装JRE 安装Maven 安装MySQL 给mysql导入数据 安装Redis 安装kafka 安装ElasticSearch Wkhtmltopdf 安装tomcat ...
- 仿牛客社区项目(第一章)
文章目录 第一章:初始 SpringBoot,开发社区首页 仿牛客社区项目开发首页功能 一. 实体引入 1. User类 2. DiscussPost 类 3. Page类 二. 配置文件 三. da ...
- 仿牛客论坛项目(上)
代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(下) 仿牛客论坛项目上 1. Spring 在测试类中使用Spring环境 @Primary的作用 @ ...
最新文章
- 【C++自我精讲】基础系列二 const
- python画正方形-用Python Turtle画一个正方形
- 监控j服务器jvm运行情况 - spring boot jvisualvm
- [Android]ListView控件之Adapter性能优化
- Microsoft RTF栈溢出漏洞(CVE-2010-3333)漏洞分析
- C语言高级技巧-在Makefile中引用你的头文件
- Java线程面试题 Top 50
- 硬件知识:串口通讯的起始、数据、停止位是怎么分配的?
- 真香系列-JSFinder实用改造
- 海南省重点公共场所WiFi覆盖率达到97.7%
- 机器学习-西瓜书、南瓜书第五章
- 将 Android* x86 NDK 供 Eclipse* 而移植 NDK 演示示例应用程序
- Windows10键盘快捷键大全
- 大数据hadoop讲解
- Gravity:环形二维码扫描识别传感器详细介绍和工作原理
- Java-springboot生鲜电商项目(一)数据设计与项目初始化
- 免费云服务器+免费虚拟主机推荐
- Hive设置连接用户名和密码
- 前端企业微信开发内嵌H5记录
- 【转贴】[原创]V刹安装调整体会
热门文章
- GITHUB设置代理——解决git clone下载过慢的问题
- android shape大小,Android shape属性详解
- 太阳能光伏发电整流逆变实训装置,QY-TF01
- 创建压缩文件时,Keka总是询问每一次文件名的解决方法
- The Top 100 Masterpieces of Classical Music 古典音乐100首经典杰作
- 从华为云到米家APP,智能家居行业如何突破发展?智能家居未来发展方向(下)
- Ubuntu远程拷贝SCP问题
- 让程序在崩溃时体面的退出之总结
- oracle 视图 自增列,Oracle实现自增列
- ICLR2021放榜~6篇SOTA GNN论文推荐