【Linux】线程同步条件变量

news2024/12/24 20:16:30

文章目录

  • 一. 为什么要线程同步
  • 二. 条件变量
    • 1. 条件变量的使用
    • 2. 简单使用
  • 结束语

一. 为什么要线程同步

通过互斥量,也就是加锁解锁,我们可以实现线程互斥,但是当访问的临界区代码较少时,线程执行会出现不停加锁解锁的情况。这样一会导致线程效率降低,二会导致其他线程无法访问到临界资源,从而出现饥饿问题
为了避免出现不断加锁解锁的情况,我们需要让使用完锁的线程,不能立刻重新申请锁,并且等待锁资源的其他线程,需要按照一定顺序进行等待。这就是线程同步

在这里插入图片描述

二. 条件变量

1. 条件变量的使用

当线程互斥地访问某个变量时,它可能会发现,在其他线程改变状态前,它什么也做不了
例如一个队列要读取队列的数据,但是当他发现队列为空时,那么他只能等待,等待其他线程将数据添加到队列中。这种情况就需要用到条件变量

  • 同步: 在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,这就叫做同步
  • 竞争条件: 因为时序问题,而导致程序异常,我们称之为竞态条件

Linux中,条件变量是定义的一个联合体嵌套结构体,由操作系统帮我们维护
在这里插入图片描述


条件变量初始化

条件变量有两种初始化方式

静态初始化

同互斥量(锁)一样,操作系统提供静态的条件变量

//静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

该方法初始化的静态变量不需要手动销毁。

动态初始化

//动态初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr *restrict attr);

cond:需要初始化的条件变量的指针
attr:条件变量的属性,传nullptr代表使用默认属性


条件变量销毁

条件变量在使用完后同样也需要销毁

//条件变量销毁
int pthread_cond_destroy(pthread_cond_t *cond);

cond:需要销毁的条件变量的指针


因为线程同步是要让访问同一临界区的线程按顺序访问,所以当线程开始运行时,我们需要让他们都先等待,然后由用户指定唤醒,就可以形成一定的顺序

等待条件满足

//等待条件
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

cond:要在这个条件变量上等待
mutex:互斥量。因为等待时,线程是持有锁的,让线程等待意味着不会运行,所以需要解锁。

调用这个函数后,线程会在该条件变量上等待,直到被唤醒。等待前会解锁,唤醒后会加锁。

唤醒等待

//唤醒在该条件变量上等待的所有线程
int pthread_cond_broadcast(pthread_cond_t *cond);
//唤醒在该条件变量等待的某一个线程
int pthread_cond_signal(pthread_cond_t *cond);

cond:需要唤醒的条件变量


2. 简单使用

接下来,我们简单做个demo展示一下条件变量的使用

我们创建5个线程,然后让5个线程都在条件变量上等待,然后一个一个唤醒

#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<string>

using namespace std;

//条件变量

//静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//静态锁
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

//启动函数
void*Action(void*args)
{
    string name=static_cast<const char*>(args);

    while(true)
    {
        //申请锁
        pthread_mutex_lock(&mutex);

        //等待唤醒
        pthread_cond_wait(&cond,&mutex);
        cout<<name<<" 运行"<<endl;

        //解锁
        pthread_mutex_unlock(&mutex);
    }

    return nullptr;
}

int main()
{
    pthread_t tids[5];

    //创建5个线程
    for(int i=0;i<5;++i)
    {   
        //线程名
        char *name=new char[32];
        snprintf(name,32,"thread-%d",i+1);

        pthread_create(tids+i,nullptr,Action,name);
    }

    sleep(3);
    
    //挨个唤醒
    while(true)
    {
        cout<<"主线程唤醒线程..."<<endl;
        pthread_cond_signal(&cond);
        sleep(1);
    }

    for (int i = 0; i < 5; i++)
    {
        pthread_join(tids[i], nullptr);
    }
    return 0;
}

在这里插入图片描述

我们也可以一次性全部唤醒

	//唤醒
    while(true)
    {
        cout<<"主线程唤醒线程..."<<endl;
        //pthread_cond_signal(&cond);
        pthread_cond_broadcast(&cond);
        sleep(1);
    }

在这里插入图片描述

结束语

感谢你的阅读

如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

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

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

相关文章

uniapp项目中使用vue3开发多端项目实践

目录 1、使用版本说明2、创建项目3、运行项目4、uniapppinia本地缓存插件PiniaPluginUnistorage5、 uni-app vue3 vite ts 项目结构 本项目中使用vue3开发多端项目实践&#xff0c;hbuilderx内置vue3模块&#xff0c;使用了vite4.x构建&#xff0c;编译构建项目的速度比火箭…

dpmsolver 论文核心整理

推导 DPM-Solver1的误差 由正文所述&#xff1a; 利用泰勒展开&#xff1a; B.3式就是换了个元 δ λ − λ s λ t − λ s \delta\frac{\lambda-\lambda_s}{\lambda_t-\lambda_s} δλt​−λs​λ−λs​​&#xff0c;代入论文公式(3.4)的积分项&#xff08;不含系数&…

一套完整的工厂车间现场管理指南,车间主管收藏好了!

车间是企业的基本层&#xff0c;搞好车间现场管理&#xff0c;有利于企业增强竞争力&#xff0c;提高产品质量和员工素质&#xff0c;保证安全生产&#xff0c;而车间班组长是生产线的主要管理者&#xff0c;是直接“当家人”&#xff0c;对生产现场状况了如指掌&#xff0c;对…

0001Java程序设计-SSM校园快递系统的设计与实现

摘 要 21世纪之后&#xff0c;全球信息化逐渐加快&#xff0c;尤其表现在近几年来电商行业的飞速发展&#xff0c;人们足不出户就可以买到自己想要的商品&#xff0c;尤其是青年大学生&#xff0c;追求新颖&#xff0c;更加乐忠于网络购物。网络购物的增加&#xff0c;就导致物…

【二】python爬虫进行AES解密遇到的问题

1、TypeError: Object type <class ‘str’> cannot be passed to C code 报错如下&#xff1a; File "C:\Python311\Lib\site-packages\Crypto\Util\_raw_api.py", line 143, in c_uint8_ptrraise TypeError("Object type %s cannot be passed to C cod…

【使用Spring Cloud Gateway构建微服务网关】—— 每天一点小知识

&#x1f4a7; 使用 S p r i n g C l o u d G a t e w a y 构建微服务网关 \color{#FF1493}{使用Spring Cloud Gateway构建微服务网关} 使用SpringCloudGateway构建微服务网关&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主…

54 KVM工具使用指南-vmtop使用指南

文章目录 54 KVM工具使用指南-vmtop使用指南54.1 概述54.1.1 多架构支持54.1.2 显示项说明54.1.2.1 AArch64和x86_64架构公共显示项54.1.2.2 仅AArch64架构的显示项54.1.2.3 仅x86_64架构的显示项 54.2 使用方法54.2.1 语法格式54.2.2 选项说明54.2.3 快捷键 54.3 示例 54 KVM工…

MSP432学习笔记10:串口接收字符串命令并执行任务

今日终于得以继续我的MSP432电赛速通之路&#xff1a; 串口通信是单片机需要学习深入的一个很重要的板块&#xff0c;通过串口&#xff0c;我们可以实现许多数据收发与调试工作&#xff0c;可谓是非常方便快捷。 今日就跟随我的脚步&#xff0c;逐步扎实地学习如何编程MSP432…

2023-06-21:redis中什么是BigKey?该如何解决?

2023-06-21&#xff1a;redis中什么是BigKey&#xff1f;该如何解决&#xff1f; 答案2023-06-21&#xff1a; 什么是bigkey bigkey是指存储在Key-Value数据库中的键对应的值所占用的内存空间较大。举个例子&#xff0c;如果值是字符串类型&#xff0c;它可以达到最大512MB的…

堆体系结构概述

1、逻辑概述 2、堆会出现的异常 3、物理上划分 &#xff08;1&#xff09;新生区 新生区是类的诞生、成长、消亡的区域&#xff0c;一个类在这里产生&#xff0c;应用&#xff0c;最后被垃圾回收器收集&#xff0c;结束生命。新生区又分为两部分&#xff1a; 伊甸区&#xff0…

Goby 漏洞发布|WordPress User Post Gallery 插件 upg_datatable 远程代码执行漏洞(CVE-2022-4060)

漏洞名称&#xff1a;WordPress User Post Gallery 插件 upg_datatable 远程代码执行漏洞&#xff08;CVE-2022-4060&#xff09; English Name&#xff1a;WordPress plugins User Post Gallery upg_datatable RCE Vulnerability (CVE-2022-4060) CVSS core: 9.8 影响资产数…

Observability:如何把 Elastic Agent 采集的数据输入到 Logstash 并最终写入到 Elasticsearch

在之前的文章 “安装独立的 Elastic Agents 并采集数据 - Elastic Stack 8.0”&#xff0c;我们详述了如何使用 No Fleet Server 来把数据写入到 Elasticsearch 中。在今天的文章中&#xff0c;我们来详述如下使用 Elastic Agents 在独立&#xff08;standalone&#xff09;模式…

Gradio Blocks:自定义交互式Web应用和演示

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

GitPySearch: 全局Python代码搜索工具

一 、背景 在某些情况下&#xff0c;我们需要快速了解哪些项目包含特定的配置&#xff0c;例如使用了fastjson库或数据库的连接配置。然而&#xff0c;在GitLab上逐个代码仓库进行搜索是非常耗时的。为了提高效率&#xff0c;我们开发了一个Python脚本工具&#xff0c;用于实现…

PostgreSQL的优势:为何它成为主流数据库管理系统

PostgreSQL的优势&#xff1a;为何它成为主流数据库管理系统 Stack Overflow 2023年报告PostgreSQL和MySQL同异我们在开发中如何选择PostgreSQL和MySQL呢&#xff1f; 摘要&#xff1a;本文主要比较了PostgreSQL和MySQL这两个流行的关系型数据库管理系统。我们首先介绍了它们的…

屏蔽箱的材质结构和使用事项介绍

屏蔽箱是一种用于屏蔽机电波干扰的设备&#xff0c;通常用于电磁兼容测试、天线测试、短波收发等需要屏蔽电磁辐射噪声的场合。这种箱子通常由导电或者导磁材料制成&#xff0c;内部配备高效屏蔽材料&#xff0c;能够在一定范围内有效地屏蔽电磁波辐射&#xff0c;避免电磁波干…

详细介绍mysql索引类型

目录 Normal 普通索引Unique 唯一索引Full Text 全文索引SPATIAL 空间索引btree索引和hash索引的区别在实际操作过程中&#xff0c;应该选取表中哪些字段作为索引&#xff1f; Normal 普通索引 表示普通索引&#xff0c;大多数情况下都可以使用 Unique 唯一索引 表示唯一的&…

Linux内核内存管理源码分析之init-mm.c(2)

接前一篇文章&#xff1a;Linux内核内存管理源码分析之init-mm.c&#xff08;1&#xff09; 本文内容参考&#xff1a;https://www.cnblogs.com/mysky007/p/12317831.html 上回说到了swapper_pg_dir和init_top_gpt。再次给出内核源码中init_top_gpt的说明&#xff0c;在Documen…

【基础】MQTT -- MQTT 特性:QoS、Retained 消息、LWT 以及 Keepalive

MQTT -- MQTT 特性&#xff1a;QoS、Retained 消息、LWT 以及 Keepalive QoS 及其最佳实践MQTT 协议中的 QoS 等级QoS 0QoS 1PUBACK 数据包 QoS 2PUBREC 数据包PUBREL 数据包PUBCOMP 数据包 实际的订阅者 QoSQoS 的最佳实践QoS 与会话QoS 的选择 Retained 消息LWT 遗嘱消息Keep…

FPGA_学习_12_IP核_FIFO

FIFO(Frist Input Frist Output)&#xff0c;即先入先出&#xff0c;也是一种存储器&#xff0c;一般做数据缓冲。FIFO和 RAM的共同点在于都能存储数据、都有控制写和读的信号;不同点在于 FIFO 没有地址&#xff0c;所以不能任意指定读取某一个数据&#xff0c;数据只能按照数据…