Linux 多线程 生产者消费者 问题

news2025/1/22 17:03:17

在 Linux 系统中,生产者和消费者问题是一个经典的多线程同步问题,用于描述如何在多线程环境中协调多个线程对共享资源的访问。这个问题通常涉及两个类型的线程:生产者线程和消费者线程。生产者线程负责生成数据并将其放入缓冲区,而消费者线程则从缓冲区中取出数据进行处理。

生产者和消费者问题的基本概念

  1. 生产者(Producer):

    • 生成数据并将其放入共享缓冲区。
    • 生产者必须在缓冲区满时等待,直到有空间可用。
  2. 消费者(Consumer):

    • 从共享缓冲区中取出数据进行处理。
    • 消费者必须在缓冲区空时等待,直到有数据可用。

共享资源和同步机制

为了确保线程安全并避免竞态条件,生产者和消费者通常使用以下同步机制:

  1. 互斥锁(Mutex):

    • 用于确保只有一个线程可以在任何给定时间内访问共享缓冲区。
    • 通过锁定和解锁操作来实现。
  2. 条件变量(Condition Variable):

    • 用于让线程在某些条件下等待或唤醒。
    • 生产者在缓冲区不满时发信号唤醒消费者,消费者在缓冲区有数据时发信号唤醒生产者。

让我们用一个更生动的例子来解释生产者-消费者问题中的条件变量和互斥锁的工作机制。

例子:餐厅的厨师和服务员

想象一下,有一个餐厅,里面有一个厨房(缓冲区)和一个用餐区。餐厅有两种工作人员:厨师(生产者)和服务员(消费者)。他们之间的协调就像在处理生产者-消费者问题。

场景设置
  • 厨房有一个有限大小的桌子(缓冲区),桌子上可以放一定数量的菜(数据)。
  • 厨师做菜(生产数据)并把菜放到桌子上。
  • 服务员从桌子上拿菜(消费数据)并把菜送到顾客那里。
  • 如果桌子满了,厨师就不能放菜,需要等待服务员拿走菜。
  • 如果桌子空了,服务员就不能拿菜,需要等待厨师放菜。
具体流程
  1. 厨师做菜并放在桌子上:

    • 厨师首先检查桌子上有没有空位。
    • 如果桌子满了,厨师就等待(进入等待状态)。
    • 如果桌子有空位,厨师把菜放在桌子上,然后通知服务员桌子上有新菜了。
    • 厨师然后继续做下一道菜。
  2. 服务员拿菜并送到顾客那里:

    • 服务员首先检查桌子上有没有菜。
    • 如果桌子空了,服务员就等待(进入等待状态)。
    • 如果桌子上有菜,服务员拿走菜并送到顾客那里,然后通知厨师桌子上有空位了。
    • 服务员然后继续拿下一道菜。

代码对应的具体场景

以下代码片段展示了这个过程:

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

#define BUFFER_SIZE 10

int buffer[BUFFER_SIZE];
int count = 0;

pthread_mutex_t mutex;
pthread_cond_t cond_producer;
pthread_cond_t cond_consumer;

void* producer(void* arg) {
    while (1) {
        // 生成数据(例如:随机数)
        int item = rand() % 100;

        pthread_mutex_lock(&mutex);

        // 等待缓冲区有空位
        while (count == BUFFER_SIZE) {
            pthread_cond_wait(&cond_producer, &mutex);
        }

        // 将数据放入缓冲区
        buffer[count++] = item;
        printf("Produced: %d\n", item);

        // 通知消费者有数据可用
        pthread_cond_signal(&cond_consumer);
        
        pthread_mutex_unlock(&mutex);

        // 模拟生产时间
        sleep(1);
    }
}

void* consumer(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);

        // 等待缓冲区有数据
        while (count == 0) {
            pthread_cond_wait(&cond_consumer, &mutex);
        }

        // 从缓冲区取出数据
        int item = buffer[--count];
        printf("Consumed: %d\n", item);

        // 通知生产者有空位可用
        pthread_cond_signal(&cond_producer);
        
        pthread_mutex_unlock(&mutex);

        // 模拟消费时间
        sleep(1);
    }
}

int main() {
    pthread_t producer_thread, consumer_thread;

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond_producer, NULL);
    pthread_cond_init(&cond_consumer, NULL);

    pthread_create(&producer_thread, NULL, producer, NULL);
    pthread_create(&consumer_thread, NULL, consumer, NULL);

    pthread_join(producer_thread, NULL);
    pthread_join(consumer_thread, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond_producer);
    pthread_cond_destroy(&cond_consumer);

    return 0;
}

运行结果:

解释
  1. 互斥锁(pthread_mutex_t mutex)

    • 互斥锁就像厨房的门,确保只有一个厨师或服务员可以进出厨房,以防止混乱。
  2. 条件变量(pthread_cond_t cond_producer 和 pthread_cond_t cond_consumer)

    • 条件变量就像门口的信号灯。
    • cond_producer 是厨师用来等待服务员拿走菜的信号灯。
    • cond_consumer 是服务员用来等待厨师放菜的信号灯。
  3. 厨师(producer)

    • 厨师检查厨房的桌子(缓冲区)是否满了。
    • 如果满了,厨师等待(等待cond_producer信号)。
    • 如果有空位,厨师放菜在桌子上,并通知服务员(发送cond_consumer信号)。
    • 然后,厨师离开厨房(解锁互斥锁),继续做下一道菜。
  4. 服务员(consumer)

    • 服务员检查厨房的桌子(缓冲区)是否有菜。
    • 如果桌子空了,服务员等待(等待cond_consumer信号)。
    • 如果有菜,服务员拿走菜,并通知厨师(发送cond_producer信号)。
    • 然后,服务员离开厨房(解锁互斥锁),继续送菜给顾客。

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

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

相关文章

2024年端午节放假通知

致尊敬的客户以及全体同仁&#xff1a; 2024年端午节将至&#xff0c;根据国务院办公厅通知精神&#xff0c;结合公司的实际情况&#xff0c;现将放假事宜通知如下&#xff1a; 2024年6月8日&#xff08;星期六&#xff09;至6月10日&#xff08;星期一&#xff09;&#xff…

一个简单的方式看看MySQL的锁

突然发现半个月没写了。最近事情太多了。 在日常工作的处理问题的过程中&#xff0c;我发现了一个简单的论证锁的问题&#xff0c;以前我讲的有点复杂&#xff0c;看来应该去改改之前的讲法了。 首先构造一个无主键无索引的表。并且初始化5条数据。 场景A&#xff1a; RR隔离…

颠沛流离学二叉树(完结撒花篇)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

[机器学习] 低代码机器学习工具PyCaret库使用指北

PyCaret是一个开源、低代码Python机器学习库&#xff0c;能够自动化机器学习工作流程。它是一个端到端的机器学习和模型管理工具&#xff0c;极大地加快了实验周期&#xff0c;提高了工作效率。PyCaret本质上是围绕几个机器学习库和框架&#xff08;如scikit-learn、XGBoost、L…

【Kubernetes】k8s集群的污点、容忍、驱逐 以及排障思路

污点和容忍以及驱逐 一、污点&#xff08;Taint&#xff09; 污点介绍 节点亲和性&#xff0c;是Pod的一种属性&#xff08;偏好或硬性要求&#xff09;&#xff0c;它使Pod被吸引到一类特定的节点。Taint 则相反&#xff0c;它使节点能够排斥一类特定的 Pod。 Taint 和 Tol…

【ai】livekit服务本地开发模式1:example app信令交互详细流程

文档要安装git lfs 下载当前最新版本1.6.1windows版本:启动dev模式 服务器启动 (.venv) PS D:\XTRANS\pythonProject\LIVEKIT> cd .

python实现——分类类型数据挖掘任务(图形识别分类任务)

分类类型数据挖掘任务 基于卷积神经网络&#xff08;CNN&#xff09;的岩石图像分类。有一岩石图片数据集&#xff0c;共300张岩石图片&#xff0c;图片尺寸224x224。岩石种类有砾岩&#xff08;Conglomerate&#xff09;、安山岩&#xff08;Andesite&#xff09;、花岗岩&am…

【笔记】Sturctured Streaming笔记总结(Python版)

目录 相关资料 一、概述 1.1 基本概念 1.2 两种处理模型 &#xff08;1&#xff09;微批处理 &#xff08;2&#xff09;持续处理 1.3 Structured Streaming和Spark SQL、Spark Streaming关系 二、编写Structured Streaming程序的基本步骤 三、输入源 3.1 File源 &a…

python-题库篇-为什么数组下标从0 开始而不是 1

为什么很多编程语言要把 0 作为第一个下标索引&#xff0c;而不是直观的 1 呢&#xff1f; 这个问题 Dijkstra 已经解答过了&#xff0c;没错&#xff0c;就是你知道的 Dijkstra&#xff0c;Dijkstra 最短路径算法&#xff0c;荷兰语全名是 Edsger Wybe Dijkstra&#xff0c;于…

linux查看磁盘类型命令

在Linux中&#xff0c;有多种方法可以查看磁盘是固态硬盘&#xff08;SSD&#xff09;还是机械硬盘&#xff08;HDD&#xff09;。以下是一些常用的方法&#xff1a; 查看/sys/block/目录 /sys/block/目录包含了系统中所有块设备的信息。你可以查看这个目录中的设备属性来判断…

保姆级教程:Redis 主从复制原理及集群搭建

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

LabVIEW在高校电力电子实验中的应用

概述&#xff1a;本文介绍了如何利用LabVIEW优化高校电力电子实验&#xff0c;通过图形化编程实现参数调节、实时数据监控与存储&#xff0c;并与Simulink联动&#xff0c;提高实验效率和数据处理能力。 需求背景高校实验室在进行电机拖动和电力电子实验时&#xff0c;通常使用…

文献解读-肿瘤测序-第五期|《局部晚期或转移性儿童及青少年分化型甲状腺癌的基因特征与临床特征及131I疗效的关系》

关键词&#xff1a;应用遗传流行病学&#xff1b;群体测序&#xff1b;肿瘤测序&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;The relationship between genetic characteristics and clinical characteristics and the efficacy of 131I therapy in c…

opencv笔记(13)—— 停车场车位识别

一、所需数据介绍 car1.h5 是训练后保存的模型 class_directionary 是0&#xff0c;1的分类 二、图像数据预处理 对输入图片进行过滤&#xff1a; def select_rgb_white_yellow(self,image): #过滤掉背景lower np.uint8([120, 120, 120])upper np.uint8([255, 255, 255])#…

【YOLO系列】YOLOv10论文超详细解读(翻译 +学习笔记)

前言 研究AI的同学们面对的一个普遍痛点是&#xff0c;刚开始深入研究一项新技术&#xff0c;没等明白透彻&#xff0c;就又迎来了新的更新版本——就像我还在忙着逐行分析2月份发布的YOLOv9代码&#xff0c;5月底清华的大佬们就推出了全新的v10。。。 在繁忙之余&#xff0…

opencv进阶 ——(九)图像处理之人脸修复祛马赛克算法CodeFormer

算法简介 CodeFormer是一种基于AI技术深度学习的人脸复原模型&#xff0c;由南洋理工大学和商汤科技联合研究中心联合开发&#xff0c;它能够接收模糊或马赛克图像作为输入&#xff0c;并生成更清晰的原始图像。算法源码地址&#xff1a;https://github.com/sczhou/CodeFormer…

深度学习论文: DINOv2: Learning Robust Visual Features without Supervision

深度学习论文: DINOv2: Learning Robust Visual Features without Supervision DINOv2: Learning Robust Visual Features without Supervision PDF: https://arxiv.org/abs/2304.07193 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://githu…

Transformer系列:注意力机制的优化,MQA和GQA原理简述

前言 多查询注意力(MQA)、分组查询注意力(GQA)是Transformer中多头注意力(MHA)的变种&#xff0c;它们大幅提高了解码器的推理效率&#xff0c;在LLaMA-2&#xff0c;ChatGLM2等大模型中有广泛使用&#xff0c;本篇介绍MQA、GQA的原理并分析其源码实现。 使用MQA&#xff0c;G…

Spring Boot前后端简单集成MinIo开发

Spring Boot前后端简单集成MinIo开发 源码地址重要配置和代码MinIO配置核心代码 最终效果 源码地址 minioStudy 重要配置和代码 MinIO配置 pom文件引入依赖 <!-- minio --> <dependency><groupId>io.minio</groupId><artifactId>minio</ar…

GaussDB的数种形态

GaussDB作为一种新兴的关系型数据库产品&#xff0c;似乎有点让人摸不着头脑。有朋友问我GaussDB单机版怎么样&#xff0c;有人说GaussDB是分布式数据库&#xff0c;还有人说它是云数据库&#xff0c;还有人会把GaussDB和华为的数据仓库GaussDB DWS混为一谈。确实&#xff0c;公…