Linux线程同步(条件变量)

news2024/12/28 19:35:01

文章目录

  • 前言
  • 一、条件变量概念
  • 二、条件变量相关的函数
  • 三、条件变量模拟生产者消费者模型
  • 四、使用条件变量的好处
  • 总结


前言

本篇文章来讲解一下条件变量的使用。

一、条件变量概念

条件变量(Condition Variable)是并发编程中一种线程同步机制,用于实现线程之间的等待和通知机制。它是一种与特定条件相关的线程同步原语。

条件变量用于线程间的协调,允许一个线程在满足某个特定条件之前等待,并在其他线程满足条件后被通知继续执行。它通常与互斥锁(Mutex)结合使用,以提供更精细的线程同步和共享数据的访问控制。

条件变量的基本概念包括以下几个要素:

1.等待和通知:
条件变量提供了等待和通知的机制,等待(Wait)操作用于使线程进入等待状态,直到满足某个特定条件。通知(Signal或Broadcast)操作用于唤醒等待中的线程,告知它们条件已经满足。

2.互斥锁:
在使用条件变量之前,通常需要先获取与之配套的互斥锁,以确保共享数据的互斥访问。互斥锁用于保护与条件相关的共享资源,以防止多个线程同时访问。

3.条件谓词:
条件变量通常与条件谓词(Condition Predicate)一起使用,条件谓词是描述条件是否满足的谓词表达式。在线程等待之前和通知之后,都需要通过条件谓词进行条件的检查。

条件变量的典型用法包括以下步骤:

1.线程获取互斥锁,锁定共享资源。

2.检查条件谓词,判断是否满足等待条件,如果不满足则等待条件变量。

3.线程释放互斥锁并进入等待状态,直到其他线程发出通知。

4.当其他线程满足条件变量的条件并发出通知时,等待中的线程被唤醒。

5.线程重新获取互斥锁,继续执行后续操作。

条件变量的使用可以避免线程的忙等待,提高程序的效率,并且更加灵活地实现线程间的通信和同步。但在使用条件变量时需要注意正确的加锁和解锁的顺序,以避免死锁和竞态条件等并发编程的常见问题。

二、条件变量相关的函数

条件变量在Linux下使用一些常见的函数来实现线程之间的同步和通信。下面是条件变量使用的几个常用函数:

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,失败返回错误码。
在调用 pthread_cond_wait() 之前,必须先获得与条件变量关联的互斥锁 mutex 的锁,然后该函数会自动释放 mutex 的锁,并让线程进入等待状态,直到被另一个线程通过 pthread_cond_signal() 或 pthread_cond_broadcast() 唤醒。

4.pthread_cond_signal():用于唤醒一个正在等待条件变量的线程。

int pthread_cond_signal(pthread_cond_t *cond);

参数 cond:指向要唤醒的条件变量。
返回值:成功返回0,失败返回错误码。
pthread_cond_signal() 会唤醒等待 cond 条件变量的一个线程,如果没有线程在等待条件变量,则该函数调用没有任何效果。

5.pthread_cond_broadcast():用于唤醒所有正在等待条件变量的线程。

int pthread_cond_broadcast(pthread_cond_t *cond);

参数 cond:指向要广播的条件变量。
返回值:成功返回0,失败返回错误码。
pthread_cond_broadcast() 会唤醒等待 cond 条件变量的所有线程,即广播唤醒所有等待的线程。

三、条件变量模拟生产者消费者模型

示例代码:

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

#define BUFFER_SIZE 10

typedef struct {
    int buffer[BUFFER_SIZE];
    int count;
    int in;
    int out;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
} Buffer;

Buffer buffer;

void* producer(void* arg) 
{
    int item = 1;
    while (1) 
    {
        pthread_mutex_lock(&buffer.mutex);
        
        // 检查缓冲区是否已满
        while (buffer.count == BUFFER_SIZE) 
        {
            pthread_cond_wait(&buffer.cond, &buffer.mutex);
        }
        
        // 写入数据并更新缓冲区状态
        buffer.buffer[buffer.in] = item;
        buffer.in = (buffer.in + 1) % BUFFER_SIZE;
        buffer.count++;
        printf("生产者生产了:%d\n", item);

        // 唤醒等待的消费者线程
        pthread_cond_signal(&buffer.cond);
        
        pthread_mutex_unlock(&buffer.mutex);
        
        item++;
        sleep(1);
    }
    return NULL;
}

void* consumer(void* arg) 
{
    while (1) 
    {
        pthread_mutex_lock(&buffer.mutex);
        
        // 检查缓冲区是否为空
        while (buffer.count == 0) 
        {
            pthread_cond_wait(&buffer.cond, &buffer.mutex);
        }
        
        // 读取数据并更新缓冲区状态
        int item = buffer.buffer[buffer.out];
        buffer.out = (buffer.out + 1) % BUFFER_SIZE;
        buffer.count--;
        printf("消费者消费了:%d\n", item);
        
        // 唤醒等待的生产者线程
        pthread_cond_signal(&buffer.cond);
        
        pthread_mutex_unlock(&buffer.mutex);
        
        sleep(1);
    }
    return NULL;
}

int main(void)
{

    pthread_t producer_thread, consumer_thread;
    
    // 初始化缓冲区和相关的同步对象
    buffer.count = 0;
    buffer.in = 0;
    buffer.out = 0;
    pthread_mutex_init(&buffer.mutex, NULL);
    pthread_cond_init(&buffer.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_mutex_destroy(&buffer.mutex);
    pthread_cond_destroy(&buffer.cond);

    

    return 0;
}

运行效果:
在这里插入图片描述

四、使用条件变量的好处

1.避免资源浪费:当条件不满足时,线程可以调用pthread_cond_wait函数来等待条件满足。在等待期间,该线程会释放持有的锁,允许其他线程获得锁并继续执行临界区代码。这样可以避免空转和资源浪费。

2.避免竞争条件:条件变量的使用可以帮助避免竞争条件的发生。线程间的协作通过条件变量来实现,确保在满足特定条件之前,线程不会执行关键代码段。

3.提高并发性:条件变量使得线程能够在需要等待条件满足时休眠,而不是通过忙等待消耗处理器资源。这样可以提高系统的并发性和效率。

4.简化同步逻辑:使用条件变量可以简化同步逻辑,使代码更加清晰易懂。条件变量提供了一种灵活而有效的机制来控制线程的行为,使得编写正确的多线程代码变得更加容易。

总结

本篇文章主要讲解了条件变量的概念和条件变量的相关函数和使用条件变量模拟生产者消费者模型。

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

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

相关文章

解决阿里图标引入彩色图标却是黑色的问题

解决阿里图标引入彩色图标却是黑色的问题 下载symbol文件&#xff0c; 引入这些文件&#xff1a; 使用&#xff1a; <svg class"icon" aria-hidden"true"><use xlink:href"#icon-图标名称"></use></svg>.icon {width: …

Flowable-结束事件-取消结束事件

目录 定义图形标记XML内容使用示例视频教程 定义 取消结束事件只能与 BPMN 事务子流程结合使用&#xff0c;它可以取消一个事务子流程的执行&#xff0c;同时 也只能在子流程中执行。实际应用中&#xff0c;会把取消事件&#xff0c;事务子流程&#xff0c;补偿事件一起用。当…

实例033 制作闪烁的窗体

实例说明 Windows系统中&#xff0c;当程序在后台运行时&#xff0c;如果某个窗口的提示信息需要用户浏览&#xff0c;该窗口就会不停的闪烁&#xff0c;这样就会吸引用户的注意。同样&#xff0c;如果在自己的程序中使某个窗口不停的闪烁就会吸引用户的注意。本例设计了一个闪…

adb用法,安卓的用户CA证书放到系统CA证书下

设备需root&#xff01;&#xff01;设备需root&#xff01;&#xff01;设备需root&#xff01;&#xff01; ​​​​​​​测试环境&#xff1a;redmi 5 plus、miui10 9.9.2dev&#xff08;安卓8.1&#xff09;、已root win下安装手机USB驱动&#xff08;过程略&#xff0c…

图像的转置之c++实现(qt + 不调包)

1.基本原理 图像的转置就是将图像的横坐标和纵坐标交换位置&#xff0c;和矩阵的转置是一样的&#xff0c;公式见下&#xff1a; 2.代码实现&#xff08;代码是我以前自学图像处理时写的&#xff0c;代码很粗糙没做任何优化&#xff0c;但很好理解&#xff09; /*图像的转置函…

无涯教程-Perl - getc函数

描述 此函数从FILEHANDLE中读取下一个字符(如果未指定,则从STDIN中读取),并返回值。 语法 以下是此函数的简单语法- getc FILEHANDLEgetc返回值 此函数返回错误或文件结尾的undef以及从FILEHANDLE读取的字符值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl$k…

APT80DQ20BG-ASEMI快恢复二极管80A 200V

编辑&#xff1a;ll APT80DQ20BG-ASEMI快恢复二极管80A 200V 型号&#xff1a;APT80DQ20BG 品牌&#xff1a;ASEMI 芯片个数&#xff1a;双芯片 封装&#xff1a;TO-3P 恢复时间&#xff1a;≤50ns 工作温度&#xff1a;-55C~150C 浪涌电流&#xff1a;600A*2 正向电流…

解析Java中的包装类和泛型

Java中的包装类和泛型 一、包装类与基本类型二、泛型1、什么是泛型2、引出泛型3、泛型类的定义和使用4、擦除机制5、泛型的上界6、泛型方法7、通配符 总结 一、包装类与基本类型 包装类&#xff0c;就是基本数据类型对应的类类型。我们已知Java中有8种基本数据类型&#xff0c…

算法与数据结构(二十二)动态规划解题套路框架

动态规划解题套路框架 此文只在个人总结 labuladong 动态规划框架&#xff0c;仅限于学习交流&#xff0c;版权归原作者所有&#xff1b; 动态规划问题&#xff08;Dynamic Programming&#xff09;应该是很多读者头疼的&#xff0c;不过这类问题也是最具有技巧性&#xff0c…

BurpSuite超详细安装教程-功能概述-配置-使用教程---(附下载链接)

一、介绍 BurpSuite是渗透测试、漏洞挖掘以及Web应用程序测试的最佳工具之一&#xff0c;是一款用于攻击web 应用程序的集成攻击测试平台&#xff0c;可以进行抓包、重放、爆破&#xff0c;包含许多工具&#xff0c;能处理对应的HTTP消息、持久性、认证、代理、日志、警报。 二…

港科夜闻|追求卓越教学奖颁奖典礼成功举办,两位香港科大教授获表彰

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、2022年度追求卓越教学奖颁奖典礼于近日成功举办&#xff0c;两位香港科大教授获表彰。香港科大社会科学学部王家礼教授获得“追求卓越教学奖(The Common Core Teaching Excellence Award)”&#xff0c;香港科大公共政策…

Python小白入门:关于函数的超详解知识点总结(定义、传递参数、返回值、模块等)

本文目录 一、定义函数二、传递实参2.1 位置实参2.2 关键字参数2.3 默认值练习题代码输出 三、返回值3.1 返回简单值3.2 可选实参3.3 返回字典3.4 在函数中使用while循环练习题代码输出 四、传递列表4.1 在函数中修改列表4.2 禁止函数修改列表练习题代码输出 五、传递任意数量的…

【Linux】常用的文本处理命令详解 + 实例 [⭐实操常用,建议收藏!!⭐]

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

【雕爷学编程】Arduino动手做(195)---HT16k33 矩阵 8*8点阵屏模块6

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

Positive证书是什么?

Positive SSL是全球著名CA Sectigo的子品牌&#xff0c; 也是目前全球签发量最高的商业SSL证书。价格低&#xff0c;安全性高&#xff0c;在个人网站和中小型企业网站中拥有极高的占有率。 Positive SSL证书包括DV SSL&#xff0c; EV SSL&#xff0c;也是唯一支持IP地址加密的…

Scratch 之 TurboWarp 常用插件介绍-1

今天带来2篇 TurboWarp 常用插件介绍。 什么你还没有 TurboWarp &#xff1f;快去下载一个吧 TurboWarp&#xff08;简称TW&#xff09; 在线版 | 离线版下载 TurboWarp优点 编译速度快于原版 Scratch 至少10倍拥有自定义帧的功能&#xff08;比如60 FPS&#xff09;造型编…

【ppt技巧】PPT限制修改的两种方法

PPT文件制作完成之后&#xff0c;保护PPT文件样式以及内容&#xff0c;很重要&#xff0c;防止生成的模板不被修改也很重要。今天分享两种限制修改PPT文件的方法。 方法一&#xff1a; 想要PPT文件中添加的logo、页脚、标题样式等不被改变&#xff0c;可以将所有设置在幻灯片…

无需公网-用zerotier异地组网

无需公网-用zerotier异地组网 在前面的文章中我们讲到利用frp进行内网穿透&#xff0c;但是他的局限在于你需要一台公网服务器。并且对公网服务器的带宽有一定的要求。因此这里我们推荐一款异地组网工具搭建属于自己的虚拟网络&#xff0c;经过授权连接成功之后彼此都在同一网…

8个电商值得关注的3D模型利用技巧

赛车、咖啡机、能量饮料、餐椅、野营炊具、曲棍球棒、钻戒&#xff0c;甚至风火轮玩具车。 你可以在 Shopify 商店中找到它们&#xff0c;现在借助文件标准和 Web 渲染的最新进展&#xff0c;你可以在自己的笔记本电脑屏幕上以 3D 模型的形式看到这些精确的产品。 更重要的是&a…