【Linux操作系统】Linux系统编程中条件变量实现生产者消费者模型

news2025/1/23 12:02:57

在Linux系统编程中,条件变量是一种用于线程间同步的机制,常用于实现生产者消费者模型。生产者消费者模型是一种常见的并发编程模型,用于解决多线程环境下的数据共享和同步问题。在该模型中,生产者负责生产数据,消费者负责消费数据,而条件变量则用于在生产者和消费者之间进行同步。

在这里插入图片描述

文章目录

    • 原理
    • 相关函数
      • 1. pthread_cond_init
      • 2. pthread_cond_destroy
      • 3. pthread_cond_wait
      • 4. pthread_cond_signal
      • 5. pthread_cond_broadcast
    • 示例和代码解释

原理

条件变量是一种基于互斥锁的线程同步机制,它允许线程在满足特定条件之前等待,并在条件满足时被唤醒。在生产者消费者模型中,条件变量用于控制生产者和消费者之间的数据传递和同步。

条件变量通常与互斥锁配合使用。互斥锁用于保护共享资源,而条件变量用于在特定条件下等待和唤醒线程。当某个线程需要等待某个条件时,它会释放互斥锁并进入等待状态。当其他线程满足了条件并调用相应的函数来通知等待线程时,等待线程会被唤醒并重新获取互斥锁。

相关函数

1. pthread_cond_init

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
  • 功能:初始化条件变量
  • 参数:
    • cond:指向条件变量的指针
    • attr:条件变量的属性,通常为NULL
  • 返回值:成功返回0,失败返回错误码

2. pthread_cond_destroy

int pthread_cond_destroy(pthread_cond_t *cond);
  • 功能:销毁条件变量
  • 参数:
    • cond:指向条件变量的指针
  • 返回值:成功返回0,失败返回错误码

3. pthread_cond_wait

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
  • 功能:等待条件变量满足
  • 参数:
    • cond:指向条件变量的指针
    • mutex:指向互斥锁的指针
  • 返回值:成功返回0,失败返回错误码

4. pthread_cond_signal

int pthread_cond_signal(pthread_cond_t *cond);
  • 功能:唤醒等待条件变量的一个线程
  • 参数:
    • cond:指向条件变量的指针
  • 返回值:成功返回0,失败返回错误码

5. pthread_cond_broadcast

int pthread_cond_broadcast(pthread_cond_t *cond);
  • 功能:唤醒等待条件变量的所有线程
  • 参数:
    • cond:指向条件变量的指针
  • 返回值:成功返回0,失败返回错误码

示例和代码解释

下面是一个使用条件变量实现生产者消费者模型的示例代码:

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

#define BUFFER_SIZE 10

int buffer[BUFFER_SIZE];
int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;

void *producer(void *arg) {
    int i;
    for (i = 0; i < BUFFER_SIZE; i++) {
        pthread_mutex_lock(&mutex);
        while (count == BUFFER_SIZE) {
            pthread_cond_wait(&cond, &mutex);
        }
        buffer[count++] = i;
        printf("Produced: %d\n", i);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    pthread_exit(NULL);
}

void *consumer(void *arg) {
    int i;
    for (i = 0; i < BUFFER_SIZE; i++) {
        pthread_mutex_lock(&mutex);
        while (count == 0) {
            pthread_cond_wait(&cond, &mutex);
        }
        int item = buffer[--count];
        printf("Consumed: %d\n", item);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t producer_thread, consumer_thread;

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, 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_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}

上述代码中,我们定义了一个大小为10的缓冲区(buffer),生产者线程负责向缓冲区中生产数据,消费者线程负责从缓冲区中消费数据。

在生产者线程中,我们首先获取互斥锁,然后检查缓冲区是否已满。如果缓冲区已满,则调用pthread_cond_wait函数等待条件变量满足,此时会自动释放互斥锁。当其他线程调用pthread_cond_signal函数唤醒等待的线程时,生产者线程会被唤醒并重新获取互斥锁。然后,我们将数据放入缓冲区,打印生产的数据,并调用pthread_cond_signal函数唤醒可能等待的消费者线程。最后,释放互斥锁。

在消费者线程中,我们也首先获取互斥锁,然后检查缓冲区是否为空。如果缓冲区为空,则调用pthread_cond_wait函数等待条件变量满足,此时会自动释放互斥锁。当其他线程调用pthread_cond_signal函数唤醒等待的线程时,消费者线程会被唤醒并重新获取互斥锁。然后,我们从缓冲区中取出数据,打印消费的数据,并调用pthread_cond_signal函数唤醒可能等待的生产者线程。最后,释放互斥锁。

在主函数中,我们创建了生产者线程和消费者线程,并等待它们的完成。最后,我们销毁条件变量和互斥锁。

通过以上代码和解释,我们可以清楚地了解条件变量在生产者消费者模型中的使用。条件变量的作用是在特定条件满足时等待和唤醒线程,从而实现线程间的同步。同时,结合互斥锁的使用,可以确保线程对共享资源的访问是安全的。

在这里插入图片描述

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

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

相关文章

53 个 CSS 特效 3(完)

53 个 CSS 特效 3&#xff08;完&#xff09; 前两篇地址&#xff1a; 53 个 CSS 特效 153 个 CSS 特效 2 这里是第 33 到 53 个&#xff0c;很多内容都挺重复的&#xff0c;所以这里解释没之前的细&#xff0c;如果漏了一些之前的笔记会补一下&#xff0c;写过的就会跳过。…

【算法训练-模拟】模拟设计LRU缓存结构

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是LRU缓存结构设计&#xff0c;这类题目出现频率还是很高的&#xff0c;几乎所有大厂都常考。 当然面对这道题&#xff0c;首先要讲清楚LRU是干什么…

JavaScript—对象与构造方法

目录 json对象&#xff08;字面值&#xff09; js中对象是什么&#xff1f; 如何使用&#xff1f; 关联数组 js对象和C#对象有什么区别&#xff1f; 构造函数 什么是构造方法&#xff1f; 如何使用构造方法&#xff1f; 如何添加成员&#xff1f; 对象的动态成员 正则…

PageObject三层架构模式实现

1&#xff1a;PageObject三层架构分为&#xff1a; 接下来用163邮箱的登录功能来举例说明三层架构的使用。 1&#xff1a;先创建目录结构&#xff0c;如下图 2&#xff1a;在工具Util中&#xff0c;先封装查找元素定位的工具&#xff0c;创建一个find_ele.py文件。内容如下&am…

JavaScript—DOM(文档对象模型)

目录 DOM是什么&#xff1f; DOM有什么作用&#xff1f; 一、事件 理解事件 事件怎么写&#xff08;要做什么就写什么&#xff09;&#xff1f; 实战演练 1、页面加载完毕以后&#xff0c;打印一句话 2、如果有一个a标签&#xff0c;并给其添加一个点击事件 3、事件默…

电脑如何投屏到手机?Windows投屏到iPhone也可以吗?

我们知道&#xff0c;因为各大品牌厂商越来越维护自己的名声&#xff0c;都会推出“全家桶”&#xff0c;就是某些功能&#xff0c;你在使用同一品牌的电脑、手机、平板时非常好用&#xff0c;但一旦跨品牌就用不了。电脑投屏到手机也会遇到这种“品牌隔离”。 如果参会人使用…

对DataFrame对象中的数据将各行列进行整体平移DataFrame.shift()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 对DataFrame对象中的数据 将各行列进行整体平移 DataFrame.shift() [太阳]选择题 以下python代码错误的是? import pandas as pd dfpd.DataFrame({A:[1,2,3],B:[4,5,6]}) print(【显示】df&…

SAP MM学习笔记26- SAP中 振替转记(转移过账)和 在库转送(库存转储)3- Plant间在库转送

SAP 中在库移动 不仅有入库&#xff08;GR&#xff09;&#xff0c;出库&#xff08;GI&#xff09;&#xff0c;也可以是单纯内部的转记或转送。 1&#xff0c;振替转记&#xff08;转移过账&#xff09; 2&#xff0c;在库转送&#xff08;库存转储&#xff09; 1&#xff…

springboot+vue健身房俱乐部课程预约网站的设计与实现0356t

通过对知识内容的学习研究&#xff0c;进而设计并实现一个“力炫”健身馆网站。系统能实现的主要功能应包括&#xff1b;用户、健身教练、健身器材、健身课程、健身商品、健身资讯等的一些操作&#xff0c;传统的管理模式主要是使用纸作为介质&#xff0c;信息交流很大程度上受…

ASL芯片CS5366带DSC影像解压 替代PS186替代RTD2173替代AG9411 集睿致远方案设计优势

CS5366是ASL集睿致远推出的2LAN带PD&#xff08;最高100W&#xff09;可拉U3口的高集成度芯片&#xff0c;分辨率支持4K60HZ。在刷新率上&#xff0c;CS5366作为升级一代&#xff0c;超越了CS5266达到60HZ&#xff0c;同时在各个方面做到了优越性&#xff0c;极具性价比的一代&…

如何使用CSS实现一个自适应等高布局?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Flexbox 布局⭐ 使用 Grid 布局⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发…

海康VisionMaster-全局变量-全局脚本-全局通讯

using System; using VM.GlobalScript.Methods; using System.Windows.Forms; using iMVS_6000PlatformSDKCS; using System.Runtime.InteropServices;/******************************* 示例说明: 接收全局通信模块数据示例* 前提: 全局通信模块中开启有通信设备* 控制逻…

Mycat单库分表

Mycat单库分表 一、准备工作 1.MySQL主从同步、JDK。 2.mycat解压即可&#xff0c;无需安装。 3.如果用的是云服务器&#xff0c;需要开放8066端口。 二、配置文件 1.server.xml&#xff1a;定义用户以及系统相关变量&#xff0c;如端口&#xff08;默认8066&#xff0…

【golang】15、cobra cli 命令行库

Cobra 是 golang 最流行的命令行库&#xff0c;文档见 一、脚手架 mkdir pt && cd pt && go mod init cobra-cli init # 在项目下运行即可生成脚手架# tree . ├── LICENSE ├── cmd # 生成了cmd目录 │ └── root.go # 生成了root.go, 其中定义了ro…

Kubernetes(k8s)上部署redis5.0.14

Kubernetes上部署redis 环境准备创建命名空间 准备PV和PVC安装nfs准备PV准备PVC 部署redis创建redis的配置文件部署脚本挂载数据目录挂载配置文件通过指定的配置文件启动redis 集群内部访问外部链接Redis 环境准备 首先你需要一个Kubernetes环境&#xff0c;可参考我写的文章&…

LLM - Baichuan-13B 多卡加载与推理测试

目录 ​编辑 一.引言 二.模型加载 1.量化加载 ◆ 基础配置 ◆ 8_bit 加载 ◆ 4_bit 加载 2.多卡加载 ◆ API 加载 ◆ accelerate 加载 三.模型推理 1.显存查看 ◆ Nvidia 显卡监控 ◆ Python subprocess 调用 2.双卡推理 ◆ 双卡 divice 分配 ◆ 双卡推理 GPU…

Redis数据结构:Zset类型全面解析

Redis&#xff0c;作为一种高性能的键值对数据库&#xff0c;因其丰富的数据类型和高效的性能而受到了广泛的关注和使用。在 Redis 的五种主要数据类型中&#xff0c;Zset&#xff08;有序集合&#xff09;类型可能是最复杂&#xff0c;但也是最强大的一种。Zset 不仅可以存储键…

【JavaSE专栏90】用最简单的方法,使用 JDBC 连接 MySQL 数据库

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;3年JAVA全栈开发经验&#xff0c;专注JAVA技术、系统定制、远程指导&#xff0c;致力于企业数字化转型&#xff0c;CSDN学院、蓝桥云课认证讲师。 主打方向&#xff1a;Vue、SpringBoot、微信小程序 本文讲解了如何使用…

git-tf clone 路径有空格处理方案

git-tf clone 路径存在空格情况下&#xff0c;运行命令报错&#xff1b; 需要对路径进行双引号处理

汽车电子笔记之:基于AUTOSAR的电机控制器架构设计

目录 1、概述 2、AUTOSAR设计 2.1、SWC设计 2.2、PORT设计 2.3、Runnable设计 2.4、电机控制器OS实现 1、概述 电机控制器应用层的软件架构较为复杂,主要包括PMSM(Permanent-MagnetSynchronous Motor)的矢量控制算法。根据PMSM的控制算法,对算法中的软件功能进行分析&…