3.12生产者消费者模型 3.13条件变量 3.14信号量 C++实现生产者消费者模型

news2024/11/25 0:30:58

3.12生产者消费者模型

生产者消费者模型中的对象:
1、生产者
2、消费者
3、容器
若容器已满,生产者阻塞在这,通知消费者去消费;若容器已空,则消费者阻塞,通知生产者去生产。生产者可以有多个,消费者也可以有多个。容器中的数据是多个线程共享的,线程同步问题涉及到互斥量、读写锁等。
条件变量、信号量等。
在这里插入图片描述

/*
    生产者消费者模型(粗略的版本),此处不考虑容器存满
*/
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

// 创建一个互斥量
pthread_mutex_t mutex;

struct Node{
    int num;
    struct Node *next;
};

// 头结点
struct Node * head = NULL;

void * producer(void * arg) {

    // 不断的创建新的节点(头插法),添加到链表中
    while(1) {
        pthread_mutex_lock(&mutex);
        //malloc默认返回void *,类型转换为struct Node *
        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);
        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_mutex_unlock(&mutex);
        }
    }
    return  NULL;
}

int main() {

    //初始化互斥量
    pthread_mutex_init(&mutex, NULL);

    // 创建5个生产者线程,和5个消费者线程
    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]);
    }

	
    while(1) {
        sleep(10);
    }

    //释放互斥量
    pthread_mutex_destroy(&mutex);

    pthread_exit(NULL);

    return 0;
}

显示结果:
在这里插入图片描述
后续课程解决当前生产者消费者模型所存在的问题!互斥量、条件变量、信号量

3.13条件变量

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
条件变量,某个条件满足后引起阻塞或某个条件满足后解除阻塞。配合互斥锁实现线程同步。

#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);
            pthread_mutex_unlock(&mutex);
        }
    }
    return  NULL;
}

int main() {

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    // 创建5个生产者线程,和5个消费者线程
    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]);
    }

    while(1) {
        sleep(10);
    }

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    pthread_exit(NULL);

    return 0;
}

在这里插入图片描述

3.14信号量

信号量,信号灯,灯亮则表示资源可用,灯灭则表示资源不可用。信号量主要用于阻塞线程,但不保证线程安全。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
生产者信号量初始化为8,每调用一次sem_wait(&psem),生产者信号量-1,每生产一个,消费者信号量加一,当生产者信号量为0时,阻塞。
消费者部分:每调用一次sem_wait(&csem),消费者信号量-1,每消费一个,生产者信号量加一,当消费者信号量为0时,阻塞。

#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);
    }

    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() {

    pthread_mutex_init(&mutex, NULL);
    sem_init(&psem, 0, 8);
    sem_init(&csem, 0, 0);

    // 创建5个生产者线程,和5个消费者线程
    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]);
    }

    while(1) {
        sleep(10);
    }

    pthread_mutex_destroy(&mutex);

    pthread_exit(NULL);

    return 0;
}

C++实现生产者消费者模型

参考佬博客如下:
https://blog.csdn.net/qq_42214953/article/details/104878720
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/635533.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3588平台开发系列讲解(USB篇)Linux Android USB软件架构

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、高通平台USB软件架构二、USB 设备侧软件组成2.1、OTG driver2.2、Device controller driver2.3、Gadget framework2.4、Function drivers三、USB 主机侧软件3.1、Host controller driver3.2、USB core3.3、USB PHY…

chatgpt赋能python:Python取消断点的方法

Python取消断点的方法 在Python开发过程中&#xff0c;我们经常需要设置断点来帮助我们调试代码。但是&#xff0c;有时候我们可能需要取消已设置的断点。本文将介绍如何取消Python中的断点。 1. 什么是断点 在Python中&#xff0c;断点是为了帮助调试代码而设置的一个标志。…

网络层:IPv4地址

网络层&#xff1a;IPv4地址 笔记来源&#xff1a; 湖科大教书匠&#xff1a;IPv4地址概述 湖科大教书匠&#xff1a;分类编址的IPv4地址 湖科大教书匠&#xff1a;划分子网的IPv4地址 湖科大教书匠&#xff1a;无分类编址的IPv4地址 IPv4地址就是给因特网(Internet)上的每一…

零售场景梳理和运筹优化工作经验总结

文章目录 亡羊补牢不为迟零售行业规模大卷出零售新高度运筹优化实践经验 亡羊补牢不为迟 由于工作岗位变动的缘故&#xff0c;暂时要告别零售场景了。当初自己没想太多就一头扎进了“新”零售这个场景&#xff0c;迄今为止都没有针对零售场景做一个通盘的梳理&#xff0c;现在…

御2pro,带屏遥控器航测设置

御2遥控器航测设置 0 前言1 遥控器设置2 航测软件设置3 航测设置 0 前言 无人机&#xff1a;御2 或者御2 pro&#xff0c;非变焦版本遥控器&#xff1a;大疆带屏控器 RM500 1 遥控器设置 默认的遥控器控制软件CONNECT只能航拍&#xff0c;无法航测&#xff0c;必须调节为航…

Docker常用基本命令

一、docker的基础命令 1、启动docker systemctl start docker 2、关闭docker systemctl stop docker 3、重启docker systemctl restart docker 4、设置docker开机自启动 systemctl enable docker 5 &#xff0c; 查看docker运行状态&#xff08;显示绿色代表正常启动…

类和对象(再谈构造函数)

文章目录 1.再谈构造函数1.1构造函数的赋值1.2初始化列表1.3 explicit关键字 2. static成员2.1概念2.2特性2.3例题 3 .友元3.1 友元函数3.2友元类 4.内部类5.匿名对象6.拷贝对象时编译器的一些优化 1.再谈构造函数 1.1构造函数的赋值 在创建对象时&#xff0c;编译器通过调用…

使用自签发CA证书为EMQX开启双向认证

文章目录 背景信息1、CA证书信任模型2、创建证书2.1 Root CA 证书创建2.2 emqx 服务端证书签发2.3 中间CA证书签发2.4 设备证书签发 3、配置EMQX服务端证书4、客户端使用TLS连接EMQX 背景信息 本文主要介绍了通过建立三层CA证书链&#xff0c;为EMQX集群提供PKI服务&#xff0c…

STM32基于库函数新建工程模板

基于库函数版本 准备资料&#xff1a; a) V3.5 固件库包&#xff1a;STM32F10x_StdPeriph_Lib_V3.5.0 这是 ST 官网下载的固件库完 整版&#xff0c;我们光盘目录&#xff1a; 软件资料\STM32 固件库使用参考资料\STM32F10x_StdPeriph_Lib_V3.5.0 我们官方论坛下载地址&#…

C++入门(嵌入式学习)

C入门学习 前言C概述C和C的区别 引用引用概念引用性质引用的应用 C输入和赋值string字符串函数提高函数的默认值默认值的注意事项函数的重载函数重载可能产生的问题扩充 内联函数 前言 C概述 C是一种通用的高级编程语言&#xff0c;它是由Bjarne Stroustrup于20世纪80年代初在…

论文笔记:MEASURING DISENTANGLEMENT: A REVIEW OF METRICS

0 摘要 学习解缠和表示数据中的变化因素是人工智能中的一个重要问题。虽然已经取得了许多关于学习这些表示的进展&#xff0c;但如何量化解缠仍然不清楚。 虽然存在一些度量标准&#xff0c;但对它们的隐含假设、真正衡量的内容以及限制了解甚少。因此&#xff0c;当比较不同的…

睡眠脑电中的神经跨频率耦合函数

导读 人类大脑是一个紧密连接的复杂系统。虽然其结构比较固定&#xff0c;但它可以实现很多不同的功能。其中一个重要的功能是自然睡眠过程&#xff0c;这个过程可以改变意识和随意肌肉活动。在神经层面上&#xff0c;这些改变会伴随着大脑连接的变化。为了揭示这种与睡眠相关…

推荐一个好用的开发工具百宝箱

随着科技不断发展&#xff0c;越来越多的工具在网络上应运而生&#xff0c;方便我们更加高效地完成各种任务。今天我要向大家介绍一款在线工具——码加在线工具 - 做更好的工具&#xff0c;它可以帮助你轻松完成许多繁琐、复杂的工作。 首先&#xff0c;码加在线工具 是一款非…

一维信号进行小波去噪(python)

目录 小波变换小波去噪的原理小波阈值去噪的三个主要方面pywt.threshold函数进行小波去噪对ecg信号进行小波阈值去噪关于阈值输出参考 小波变换 小波变换是一种信号的时间——尺度&#xff08;时间——频率&#xff09;分析方法&#xff0c;它具有多分辨分析的特点&#xff0c…

【模型评估】ROC(Receiver operating characteristic)与 AUC

前面&#xff0c;我们提到了混淆矩阵&#xff0c;以及根据混淆矩阵进一步计算得到的敏感度&#xff08;召回率&#xff09;、特异度、精确度、准确度、F1 Score等等。那他们的前提都是要首先确定一个截断阈值。 【模型评估】混淆矩阵&#xff08;confusion_matrix&#xff09;…

理论粘贴板-背会了避免在大佬面前露馅-常更新

1.OLS说明 最小二乘法。给定序列X(x1,x2…xn),y,估计一个向量A(a0,a1.a2…)令y’a0a1x1a2x2…an*xn, 使得(y’-y)^2最小&#xff0c;计算A。 2.代码如下 来源《python机器学习实践指南》 import patsy import statsmodels.api as sm f ‘Rent ~ Zip Beds’ y, X patsy.dmat…

嘀嗒陪诊完整后台+前端全套小程序代码v1.0.8

就医相关陪护服务升级是未来发展趋势&#xff0c;嘀嗒陪诊是一个可以长期深耕持续运营的项目&#xff0c;并可借此切入拓展衔接养老、护理等领域。 嘀嗒陪诊小程序功能相对简单&#xff0c;后台也简捷&#xff0c;如果只是做个陪诊服务的小程序也基本能满足了&#xff0c;整体…

python基本语法知识(四)——包和模块

模块 例子1&#xff1a;导入某个模块中的具体功能 # 只导入time模块中的sleep方法&#xff0c;可以直接使用sleep调用不用加time. from time import sleep print("hello") sleep(500) print("fine")# 只导入time模块中的sleep方法,并给sleep起别名为sl f…

2023/6/11

BigDecima BigDecima的作用 用于小数的精确计算用来表示很大的小数 创建对象 创建对象时要注意以下细节 BigDecimal的使用和BigInteger类似&#xff0c;唯一要注意的点是&#xff1a;在使用除法时&#xff0c;如果除不尽就要设置精确到几位&#xff0c;否则报错 使用除法时的几…

模拟实现qsort函数(采用冒泡的方式),超详细!!!

函数详解和使用 函数声明 void qsort (void* base, size_t num, size_t size,int (*cmp)(const void* e1,constvoid* e2)); 头文件 stdlib.h 参数 base-- 指向要排序的数组的第一个元素的指针。 num-- 由 base 指向的数组中元素的个数。 size-- 数组中每个元素的大小&a…