C语言实现生产者消费者模型(线程、信号量、互斥锁)

2023-05-16

三个概念:生产者消费者模型、线程、信号量

1、生产者消费者模型

        利用生活中的例子,生产者生产商品,商品放在超市,消费者去超市购买(使用)商品,也就是生产者消费者模型。

        生产者生成一定的数据放在缓冲区,然后重复此过程,与此同时,消费者也在缓冲区使用这些数据。

        问题聚焦到缓冲区,既然使用同样的缓冲区,就引出了几个问题:

                a.缓冲区的先后访问顺序问题

                b.在缓冲区要满时,生产者不会在缓冲区写入数据

                c.在缓冲区要空时,消费者不会在缓冲区读取数据

2、线程

        要实现生产者消费者模型的问题,因为生产者和消费者需要同时访问同一块缓冲区,同一块内存,就需要使用到线程。

        同一个进程中的多个线程共享进程的地址空间,同个线程共享同一个全局变量,各个线程统一参与CPU的调度,线程间的执行顺序不确定。

        多个线程必须按照事先约定好的先后顺序访问全局变量,这种先后次序依赖于要解决某种问题,生产者和消费者之间就需要解决同步问题,生产者需要先生产,消费者才能消费,linux系统提供信号量实现同步问题。

        同一个时刻只能有一个线程访问资源,写入或者读取,且在缓冲区满时,生产者不会继续在缓冲区写入数据,在缓冲区空时,消费者不会继续从缓冲区读取数据,解决临界资源不被破坏,就是互斥问题,为了实现互斥,就需要互斥锁。

3、信号量

        a.信号量代表了某一类资源,其值表示系统中该资源的数量

        b.信号量是一个受保护的量,只能通过三种操作函数来访问

                sem_init()  //初始化信号量

                sem_wait()  //P操作(申请资源)

                sem_post()  //V操作(释放资源)

        c.信号量的值为非负整数

4、互斥锁

       互斥锁操作函数:   pthread_mutex_init() //初始化

                                       pthread_mutex_lock() //加锁

                                        pthread_mutex_unlock()//解锁

初始化完互斥锁之后,每个线程在访问资源时都先尝试加锁,加锁成功就可以访问资源,使用完资源之后解锁。

                

代码段:一个生产者,一个消费者

#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>

#define SIZE 5

int buff[SIZE] = {0};
sem_t sem_r;//保存可读信号量的变量,代表buf可读资源数
sem_t sem_w;//保存可写信号量的变量,代表buf可写资源数


void* producer(void* arg)//子线程
{
    while(1)
    {
        sleep(1);
        sem_wait(&sem_w);
        int i = 0;
        int data = rand()%100;
        buff[i] = data;
        ++i;
        i %= 5;
        sem_post(&sem_r);
        printf("produce:%d\n",data);
    }
}

void* consumer(void* arg)
{
    while(1)
    {
        sleep(1);
        sem_wait(&sem_r);
        int i = 0;
        int data = buff[i];
        ++i;
        i %= 5;
        sem_post(&sem_w);
        printf("consumer:%d\n",data);
    }

}

int main(int argc, char *argv[])
{ 
    srand(time(NULL));
    pthread_t p,c;//保存线程号

    if(sem_init(&sem_r,0,0) == -1)//初始化信号量
    {
        perror("sem_init");
        return -1;
    }
    if(sem_init(&sem_w,0,1) == -1)//初始化信号量
    {
        perror("sem_init");
        return -1;
    }
    if(0 != pthread_create(&p,NULL,producer,NULL))//创建子线程
    {
        perror("pthread_create");
        return -1;
    }
    if(0 != pthread_create(&c,NULL,consumer,NULL))//创建子线程
    {
        perror("pthread_create");
        return -1;
    }
    if(0 != pthread_join(p,NULL))//非阻塞等待回收子线程产生的资源
    {
        perror("pthread_join");
        return -1;
    }
    if(0 != pthread_join(c,NULL))//非阻塞等待回收子线程产生的资源
    {
        perror("pthread_join");
        return -1;
    }

    return 0;
} 

代码段:两个生产者,两个消费者

#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>

#define SIZE 5

int buff[SIZE] = {0};
sem_t sem_r;//保存可读信号量的变量,代表buf可读资源数
sem_t sem_w;//保存可写信号量的变量,代表buf可写资源数

pthread_mutex_t mutex_p;
pthread_mutex_t mutex_c;

void* producer(void* arg)//子线程
{
    while(1)
    {
        sleep(1);
        sem_wait(&sem_w);
        pthread_mutex_lock(&mutex_p);
        int i = 0;
        int data = rand()%100;
        buff[i] = data;
        ++i;
        i %= 5;
        pthread_mutex_unlock(&mutex_p);
        sem_post(&sem_r);
        printf("produce:%d\n",data);
    }
}

void* consumer(void* arg)
{
    while(1)
    {
        sleep(1);
        sem_wait(&sem_r);
        pthread_mutex_lock(&mutex_c);
        int i = 0;
        int data = buff[i];
        ++i;
        i %= 5;
        pthread_mutex_unlock(&mutex_c);
        sem_post(&sem_w);
        printf("consumer:%d\n",data);
    }

}

int main(int argc, char *argv[])
{ 
    srand(time(NULL));
    pthread_t p1,p2,c1,c2;//保存线程号

    if(sem_init(&sem_r,0,0) == -1)//初始化信号量
    {
        perror("sem_init");
        return -1;
    }
    if(sem_init(&sem_w,0,1) == -1)//初始化信号量
    {
        perror("sem_init");
        return -1;
    }
    if(0 != pthread_create(&p1,NULL,producer,NULL))//创建子线程
    {
        perror("pthread_create");
        return -1;
    }
    if(0 != pthread_create(&p2,NULL,producer,NULL))//创建子线程
    {
        perror("pthread_create");
        return -1;
    }
    if(0 != pthread_create(&c1,NULL,consumer,NULL))//创建子线程
    {
        perror("pthread_create");
        return -1;
    }
    if(0 != pthread_create(&c2,NULL,consumer,NULL))//创建子线程
    {
        perror("pthread_create");
        return -1;
    }
    if(0 != pthread_join(p1,NULL))//非阻塞等待回收子线程产生的资源
    {
        perror("pthread_join");
        return -1;
    }
    if(0 != pthread_join(p2,NULL))//非阻塞等待回收子线程产生的资源
    {
        perror("pthread_join");
        return -1;
    }
    if(0 != pthread_join(c1,NULL))//非阻塞等待回收子线程产生的资源
    {
        perror("pthread_join");
        return -1;
    }
    if(0 != pthread_join(c2,NULL))//非阻塞等待回收子线程产生的资源
    {
        perror("pthread_join");
        return -1;
    }

    return 0;
} 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言实现生产者消费者模型(线程、信号量、互斥锁) 的相关文章

  • 轻松搞定单例模式以及线程安全等问题

    单例模式 单例模式 xff08 Singleton Pattern xff09 是 Java 中最简单的设计模式之一 这种类型的设计模式属于创建型模式 xff0c 它提供了一种创建对象的最佳方式 这种模式涉及到一个单一的类 xff0c 该类
  • 设计模式之原型模式

    原型模式 定义 xff1a 指原型实例指定创建对象的种类 xff0c 并且通过拷贝这些原型创建新的对象 不需要知道任何创建的细节 xff0c 不需要调用构造函数类型 xff1a 创建型 适用的场景 类初始化消耗较多资源 xff08 比较重的
  • 设计模式之外观模式

    外观模式 概念介绍 定义与类型 定义 xff1a 又叫门面模式 xff0c 提供了一个统一的接口 xff0c 用来访问子系统中的一群接口外观模式定义了一个高层接口 xff0c 这个接口使得子系统更容易被访问或者使用类型 xff1a 结构型
  • Mac无法连接本地Linux服务器 无法ping通

    遇到的问题 xff1a 虚拟机是从Win环境下复制到Mac上的 xff0c 在Win电脑下可以直接使用Xshell远程连接 xff0c 但在Mac下 xff0c 无法连接而且Ping不通 虚拟机使用的是CentOS 7版本 解决方案 查看M
  • gazebo视角设置问题

    How can I make my objects robot appear in image raw topic when using Gazebo camera plugin Initial view after gazebo star
  • DISM命令使用小结

    DISM命令使用小结 文章目录 DISM命令使用小结操作WIM镜像说明演示 操作系统映像说明添加功能启用本地策略启用Hyper V 操作WIM镜像 说明 REM 制作镜像并添加一个分卷 dism capture image imagefil
  • ZYNQ7000-AXI GPIO详解

    摘要 AXI GPIO是ZYNQ的一个IP核 xff0c 它能够将PS侧的AXI4 Lite接口转成PL侧的IO口 xff0c 可解决PS侧IO口不够用的问题 本文就AXI GPIO的概念 作用 配置与使用做了详细说明 xff0c 展示了示
  • Android Dialer源码分析之去电流程

    Android的拨号流程 xff0c 从拨号盘的点击拨号按钮开始 xff0c DialpadFragment java span class token annotation punctuation 64 Override span spa
  • 区块链-PancakeSwap抢跑机器人

    核心思路 监听txpool xff0c 直到检测匹配符合我们的条件时购买提高gas费实现插队 核心技术 ethers或web3 xff0c 本文采用etherserc20 核心方法 1 通过ehters提供的监听方法 xff0c 监听链上的
  • ubuntu下载安装python

    背景 fuzzbench最近又重新更新了python的版本要求是python3 10 8及以上版本 xff0c 但直接使用apt get install 无法下载这一版本 xff0c 会报错无法找到 xff0c 因此记录一下解决这一问题的全
  • STC USB-CDC 虚拟串口使用

    STC USB CDC 虚拟串口使用 目前该功能只能在STC8和STC32G单片机上实现该功能 比起WCH的单片机 xff0c 这一点要远强于STC的USBCDC功能了 xff37 xff23 xff28 随便一个 xff18 位单片机上都
  • kali 卡在 started gnome display manager(更新gnome导致,非磁盘满)

    手贱更新到gnome3 解决方案 xff1a 1 进入急救模式 xff0c 我的是在grub选择界面选择advanced 那个选项里面进入的 2 先卸载桌面环境 http www cnblogs com wanghuixi p 787580
  • Pyhton语音播放

    用Pyhton实现语音播放的功能 我们都知道python比较简单 xff0c 能够实现的功能比较全面 xff0c 而且 xff0c 他还有一些你可能想不到的功能呢 xff01 今天我就来说一说如何用python实现语音播放的功能 首先呢 x
  • 控制台运行java

    控制台执行java 新建java代码 新建一个记事本文件 xff0c 将文件名改为HelloWorld java xff0c 注意 xff1a 后缀是 java 若没有显示文件后缀 xff0c 可以在资源管理器打开显示后缀 xff0c 然后
  • Ubuntu系统主机如何免密登录服务器

    一 主机端操作 Ubuntu系统主机终端执行 cd 命令 xff0c 切换到用户目录下 在用户目录下执行 ll a 执行 cat ssh id rsa pub 获取公钥并复制公钥准备粘贴到服务器 二 服务器端操作 登录服务器后 xff0c
  • 【报错】GitHub 配置域名但是显示 Domain does not resolve to the GitHub Pages server... 怎么办

    应该只是域名解析需要时间 xff0c 反正我1小时后看就正常了 xff08 提示变绿了 xff09 xff0c 等等吧 xff08 24小时内都正常 xff09
  • 计算机论文常见词汇

    quantization kw nt ze n n 量子 量子化 xff1b 分层 xff1b 数字化 differentiating 英 d f ren e t 美 d f r n et v 区别 xff0c 区分 xff1b 使不同 x
  • 每日固定时间执行一次的shell实现

    在不使用crontab定时任务的情况下 xff0c 我们如何去实现每日定时执行某个任务的工作呢 xff1f 我遇到了类似问题 xff0c 遂转换思路 xff0c 花几分钟写了个小脚本实现如下 xff1a bin bash 每日7点执行 ct
  • FTPClient上传文件storeFile失败,没有异常,切换目录操作可以成功

    FTPClient上传文件storeFile失败 xff0c 没有异常 xff0c 切换目录操作可以成功 解决方法 xff1a 有没有设置被动模式 防火墙 有没有设置被动模式 要执行下面的语句 ftpClient span class to

随机推荐

  • 知识图谱-命名实体-关系-免费标注工具-快速打标签-Python3

    知识图谱 命名实体 关系 免费标注工具 快速打标签 Python3 一 功能介绍1 代码文件夹结构2 运行环境3 自定义命名实体 关系模板4 导入文件5 选择自定义实体和关系文件6 文本标注7 撤销和取消标注8 导出和导出并退出系统9 导出
  • Ubuntu报错:Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?

    之前在Ubuntu系统安装Navicat的时候出现了这样的问题 xff0c 难为自己半天 首先是下载文件 xff0c 出现报错 xff1a navicat16 mysql cs AppImage error while loading sh
  • linux中crontab的jar文件定时任务失败原因记录

    本文章作为备忘 xff0c 若能解决朋友们的遇到的问题 xff0c 再好不过 在创建定时任务时 xff0c 所有的路径都需要写绝对路径 xff0c 包括配置文件 若定时文件为定时执行sh文件 xff0c 而sh文件中需要的配置文件也需要写绝
  • docker安装MongoDB以及redis

    一 安装Redis 以redis 4 0 9版本为例 docker pull redis 4 0 9 span class token function mkdir span usr local docker redis data span
  • linux安装好的mysql rpm -qa |grep mysql不见

    输入 xff1a rpm qa grep i mysql
  • MariaDB导入XXX.sql文件

    使用的 MariaDB5 5 52 开启数据库服务 xff1a systemctl start mariadb 要使用该脚本 xff0c 登录数据 xff0c mysql u root p 根据提示输入你安装数据库时需设置密码 xff0c
  • BaseOs之:Error: No available modular metadata for modular package

    文章目录 Error No available modular metadata for modular package先下载rpm包 xff1a 安装modular metadata生成工具 随便找一个目录 xff0c 执行git clo
  • BaseOs之:网络yum源部署

    文章目录 参考阿里mirror aliyum源 x86 arm source站点目录结构 简单分析 每个目录站点详细结构 x86 64为例 简单分析 制作x86 64的yum源 创建Packages与debug目录 复制x86 64 noa
  • Shell脚本加入开机自启动的方法:

    Shell脚本加入开机自启动的方法 xff1a Linux中脚本设定开机自启动 方法一 xff1a 1 xff0c 在某个目录下创建脚本 xff1a 例如 xff1a root hello wei sh span class token p
  • createrepo

    createrepo 是一个对rpm 文件进行索引建立的工具 大体功能就是对指定目录下的rpm文件进行检索 xff0c 把每个rpm文件的信息存储到指定的索引文件中 xff0c 这样方便远程yum命令在安装更新时进行检索 看下creater
  • 自动汇报错误工具(ABRT)

    ABRT 是一套抱著三个目标而开发出来的规模工具 xff1a 简化用户汇报软件问题的程序 在提交给开发者的报告中提供全面的信息 提供重要的故障数据以便排列优先次序及安排支持 假如你有兴趣协助开发者排列他们的工作的优先次序 xff0c 而你愿
  • centos8系module软件包管理仓库部署

    简述 CentOS8 引入新的module软件包管理机制 下面将介绍如何部署搭建本地module源 部署流程 xff1a 思路 xff1a 先制作nginx 1 14的module yaml xff08 需要微调 xff09 xff0c 然
  • grub rescue救援模式的处理

    grub rescue救援模式的处理 来源 xff1a https www cnblogs com itcomputer articles 4182344 html 我的linux在调整分区后 xff0c 出现了grub rescue gt
  • gitlab自定义头像设置

    这里写自定义目录标题 选一个自己喜欢的头像放在自建nginx服务中 可放在gitlab的nginx中 xff1a 设置gitlab修改配置 etc gitlab gitlab rb 重新加载gitlab配置最终效果 选一个自己喜欢的头像放在
  • 【无标题】

    https www cnblogs com liujuncm5 p 6713784 html 一 依赖安装 yum install y gcc c 43 43 pcre pcre devel zlib zlib devel openssl
  • shell:批量下载epel源rpms

    span class token keyword for span span class token for or select variable i span span class token keyword in span span c
  • linux静动态依赖

    安装glibc static usr bin ld cannot find lpthread usr bin ld cannot find lc
  • 修改ftp根目录

    修改 etc vsftpd vsftpd conf xff0c 加入如下三行 xff1a local root 61 chroot local user 61 YES anon root 61 local root表示使用本地用户登录到ft
  • 基于深度学习的医学图像配准综述

    原文转自 xff1a https blog csdn net weixin 41699811 article details 84314070 版权声明 xff1a 本文为CSDN博主 Timmymm 的原创文章 xff0c 遵循 CC 4
  • C语言实现生产者消费者模型(线程、信号量、互斥锁)

    三个概念 xff1a 生产者消费者模型 线程 信号量 1 生产者消费者模型 利用生活中的例子 xff0c 生产者生产商品 xff0c 商品放在超市 xff0c 消费者去超市购买 使用 商品 xff0c 也就是生产者消费者模型 生产者生成一定