Linux -- 同步与条件变量

目录

同步

条件变量

pthread_cond_t

pthread_cond_init(初始化条件变量)

pthread_cond_destroy(销毁条件变量)

pthread_cond_wait(线程等待条件变量)

重要提醒 

pthread_cond_boardcast(唤醒等待队列中的所有线程)

pthread_cond_singal(唤醒一个正在等待的线程)

代码

条件变量的使用

唤醒一个线程:

广播唤醒线程:


同步

在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,确保这些执行单元以一种有序、非冲突的方式进行交互,从而有效避免饥饿问题,叫做同步

条件变量

条件变量的主要用途是用于实现同步,在一个或多个线程等待某个特定条件变为真时,可以被阻塞(挂起),直到其他线程通知这个条件已经满足。它提供了一种机制来安全地等待某个条件,并在条件满足时唤醒等待的线程。条件变量通常与互斥锁pthread_mutex_t)一起使用,以保护共享资源和确保线程安全。

条件变量其实是一种通知机制 + 等待队列

  • 当某种特定的条件未成立时,线程在等待队列中排队
  • 当条件成立时,可以选择唤醒队头的线程或者队列中的所有线程,继续执行线程任务。

pthread_cond_t

线程库中用于条件变量的一种数据类型

pthread_cond_init(初始化条件变量)

#include <pthread.h>int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

cond:指向要初始化的条件变量的指针。

attr:指向条件变量属性对象的指针。如果只需要默认属性,可以传递 NULL

 返回值:

  • 成功时,返回 0
  • 失败时,返回错误编号。

pthread_cond_destroy(销毁条件变量)

#include <pthread.h>int pthread_cond_destroy(pthread_cond_t *cond);

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

返回值:

  • 成功时,返回 0
  • 失败时,返回错误编号。

pthread_cond_wait(线程等待条件变量)

#include <pthread.h>int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

cond:指向要等待的条件变量的指针。

mutex:指向已经加锁的互斥锁的指针。该互斥锁应该保护着与条件相关的共享数据。

返回值:

  • 成功时,返回 0
  • 失败时,返回错误编号。

重要提醒 

  • 在调用 pthread_cond_wait 时,当前线程必须持有由 mutex 指向的互斥锁。
  • 调用此函数后,pthread_cond_wait 会自动释放互斥锁,并将当前线程置为等待状态直到某个其他线程调用 pthread_cond_signal 或 pthread_cond_broadcast 来唤醒它。
  • 当前线程被唤醒后,pthread_cond_wait 会重新尝试获取互斥锁;只有成功获取到互斥锁之后,函数才会返回。
  • 返回时,互斥锁再次被当前线程持有

pthread_cond_boardcast(唤醒等待队列中的所有线程)

#include <pthread.h>int pthread_cond_broadcast(pthread_cond_t *cond);

cond:指向要广播信号的条件变量的指针。

返回值:

  • 成功时,返回 0
  • 失败时,返回错误编号。
  • 当调用 pthread_cond_broadcast 时,所有当前正在等待该条件变量的线程都会被唤醒。
  • 每个被唤醒的线程在继续执行之前会重新尝试获取与条件变量关联的互斥锁。
  • 注意,这并不意味着所有被唤醒的线程都会立即运行;它们仍然需要按照操作系统的调度算法来获得CPU时间。

pthread_cond_singal(唤醒一个正在等待的线程)

#include <pthread.h>int pthread_cond_signal(pthread_cond_t *cond);

cond:指向要发出信号的条件变量的指针。

返回值:

  • 成功时,返回 0
  • 失败时,返回错误编号。
  • 当调用 pthread_cond_signal 时,如果有线程正在等待该条件变量,则会唤醒其中一个线程。
  • 被唤醒的线程在继续执行之前会重新尝试获取与条件变量关联的互斥锁。
  • 如果没有线程在等待该条件变量,那么调用 pthread_cond_signal 将不会有任何效果。 

代码

条件变量的使用

条件变量通常与互斥锁配套使用,线程持有互斥锁了,才可以去检查某个特定的条件是否满足,满足了才能去访问临界资源,如果不满足就去排队,所以条件变量一般在加锁和解锁之间使用,所以在排队的线程曾经拥有互斥锁

线程去排队时,需要把曾经申请到的互斥锁释放掉,让其他线程去申请锁,线程不可以拿着锁去排队,否则无法达到同步,无法保持良好的并发性!所以 pthread_cond_wait 函数的参数还包括指向已经加锁的互斥锁的指针,就是为了把线程曾经申请到的互斥锁释放掉!

唤醒一个线程:

#include<iostream>
#include<string>
#include<vector>
#include<unistd.h>pthread_cond_t gcond=PTHREAD_COND_INITIALIZER;//条件变量
pthread_mutex_t gmutex=PTHREAD_MUTEX_INITIALIZER;//互斥锁void* SlaverCore(void* args)
{std::string name=static_cast<const char*>(args);//被唤醒while(true){pthread_mutex_lock(&gmutex);//加锁//一般条件变量在加锁与解锁之间使用pthread_cond_wait(&gcond,&gmutex);//等待成功,被唤醒了std::cout<<"当前被唤醒的线程为:"<<name<<std::endl;pthread_mutex_unlock(&gmutex);//解锁}
}
void* MasterCore(void* args)
{sleep(3);std::cout<<"master 开始工作..."<<std::endl;//唤醒while(true){pthread_cond_signal(&gcond);std::cout<<"master 唤醒线程..."<<std::endl;sleep(1);}
}//创建一批被控制的线程
void StartSlaver(std::vector<pthread_t> *tidsptr,int num=3)
{for(int i=0;i<num;i++){pthread_t tid;char *name=new char[64];snprintf(name,64,"slaver-%d",i+1);int n=pthread_create(&tid,nullptr,SlaverCore,name);if(n==0){std::cout<<"create success: "<<name<<std::endl;tidsptr->emplace_back(tid);}}
}//创建主线程
void StartMaster(std::vector<pthread_t> *tidsptr)
{pthread_t tid;int n=pthread_create(&tid,nullptr,MasterCore,nullptr);if(n==0)//创建成功{std::cout<<"create master success"<<std::endl;}tidsptr->emplace_back(tid);
}void WaitThread(std::vector<pthread_t> tids)
{for(auto &tid:tids){pthread_join(tid,nullptr);//等待线程}
}
int main()
{std::vector<pthread_t> tids;//存线程idStartMaster(&tids);StartSlaver(&tids,5);WaitThread(tids);return 0;
}

广播唤醒线程:

#include<iostream>
#include<string>
#include<vector>
#include<unistd.h>pthread_cond_t gcond=PTHREAD_COND_INITIALIZER;//条件变量
pthread_mutex_t gmutex=PTHREAD_MUTEX_INITIALIZER;//互斥锁void* SlaverCore(void* args)
{std::string name=static_cast<const char*>(args);//被唤醒while(true){pthread_mutex_lock(&gmutex);//加锁//一般条件变量在加锁与解锁之间使用pthread_cond_wait(&gcond,&gmutex);//等待成功,被唤醒了std::cout<<"当前被唤醒的线程为:"<<name<<std::endl;pthread_mutex_unlock(&gmutex);//解锁}
}
void* MasterCore(void* args)
{sleep(3);std::cout<<"master 开始工作..."<<std::endl;//唤醒while(true){pthread_cond_broadcast(&gcond);std::cout<<"master 唤醒线程..."<<std::endl;sleep(1);}
}//创建一批被控制的线程
void StartSlaver(std::vector<pthread_t> *tidsptr,int num=3)
{for(int i=0;i<num;i++){pthread_t tid;char *name=new char[64];snprintf(name,64,"slaver-%d",i+1);int n=pthread_create(&tid,nullptr,SlaverCore,name);if(n==0){std::cout<<"create success: "<<name<<std::endl;tidsptr->emplace_back(tid);}}
}//创建主线程
void StartMaster(std::vector<pthread_t> *tidsptr)
{pthread_t tid;int n=pthread_create(&tid,nullptr,MasterCore,nullptr);if(n==0)//创建成功{std::cout<<"create master success"<<std::endl;}tidsptr->emplace_back(tid);
}void WaitThread(std::vector<pthread_t> tids)
{for(auto &tid:tids){pthread_join(tid,nullptr);//等待线程}
}
int main()
{std::vector<pthread_t> tids;//存线程idStartMaster(&tids);StartSlaver(&tids,5);WaitThread(tids);return 0;
}

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

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

相关文章

【源码编译】windows下mingw64安装以及cmake调用

最近因为安装MIRTK库&#xff0c;太多第三方依赖了&#xff0c;太折磨了&#xff0c;学习了使用Cmake&#xff0c;有些库又需要Fortran编译器&#xff0c;VS2022里面装了但又调用不了&#xff0c;也不知道为什么&#xff0c;最后装的mingw64&#xff0c;记录一下。 1、mingw64安…

6、mysql的MHA故障切换

MHA的含义 MHA&#xff1a;master high availability&#xff0c;建立在主从复制基础上的故障切换的软件系统。 主从复制的单点问题&#xff1a; 当主从复制当中&#xff0c;主服务器发生故障&#xff0c;会自动切换到一台从服务器&#xff0c;然后把从服务器升格成主&…

OSI 网络 7 层模型

问: 请你介绍一下OSI七层网络模型物理层解决什么问题?功能原理问题 数据链路层解决什么问题功能原理 网络层解决的问题功能原理 传输层解决什么问题功能原理会话层解决什么问题功能原理: 表示层解决什么问题 应用层解决什么问题如何展示? 问: 请你介绍一下OSI七层网络模型 物…

LeetCode:104.二叉树的最大深度

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;104.二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节…

力扣1358. 包含所有三种字符的子字符串数目

给你一个字符串 s &#xff0c;它只包含三种字符 a, b 和 c 。 请你返回 a&#xff0c;b 和 c 都 至少 出现过一次的子字符串数目。 示例 1&#xff1a; 输入&#xff1a;s "abcabc" 输出&#xff1a;10 解释&#xff1a;包含 a&#xff0c;b 和 c 各至少一次的子字…

简单整理下protobuf中常用的几个工具函数

文章目录 前言使用示例定义message结构结构体赋值ByteSizeLong()GetTypeName()DebugString()ShortDebugString()CopyFrom(const MessageLite& other)Clear() Ohters总结 前言 游戏项目中使用protobuf作为双端协议通讯的方式&#xff0c;算是一种中规中矩的方法了&#xff…

信息收集1224

系列博客目录 文章目录 系列博客目录1.针对十张足球图片求出的特征组成的张量&#xff0c;它的秩是不是比十张不同物体特征组成的张量的秩低针对问题的分析&#xff1a;1. 数据的模式和相似性2. 特征的独立性3. 数据的多样性4. 张量分解的数学本质5. 噪声和数据分布的影响结论 …

WebRTC服务质量(12)- Pacer机制(04) 向Pacer中插入数据

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

双指针——快乐数

一.题目描述 202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 二.题目解析 我们要判断一个数是不是快乐数要通过它的三个性质来进行判断。这个数会一直变化&#xff0c;由它的各个位的平方和重新构成这个数。如果这个数在变化的过程中变成了1&#xff0c;那么就是快乐数…

【玩转OCR】 | 腾讯云智能结构化OCR在多场景的实际应用与体验

文章目录 引言产品简介产品功能产品优势 API调用与场景实践图像增强API调用实例发票API调用实例其他场景 结语相关链接 引言 在数字化信息处理的时代&#xff0c;如何高效、精准地提取和结构化各类文档数据成为了企业和政府部门的重要需求。尤其是在面对海量票据、证件、表单和…

nginx-rtmp服务器搭建

音视频服务器搭建 本文采用 nginx/1.18.0和nginx-rtmp-module模块源代码搭建RTMP流媒体服务器 流程 查看当前服务器的nginx版本下载nginx和nginx-rtmp-module源代码重新编译nginx&#xff0c;并进行相关配置&#xff08;nginx.conf、防火墙等&#xff09;客户端测试连接测试搭…

借助Aspose.html控件, 使用 Java 编程将 HTML 转换为 BMP

Aspose.HTML for .NET 不仅提供超文本标记语言 ( HTML ) 文件处理&#xff0c;还提供流行图像文件格式之间的转换。您可以利用丰富的渲染和转换功能将SVG文件渲染为PNG、JPG或其他广泛使用的文件格式。但是&#xff0c;我们将使用此C# 图像处理库以编程方式在 C# 中将 SVG 转换…

区块链期末复习1.1:密码学哈希函数

一、哈希函数应该具备的三个特性 1.输入可以为任意长度的字符串 2.产生固定大小输出&#xff08;比如256位&#xff09; 3.能进行有效计算。对于n位字符串&#xff0c;可以在O(n)的时间内计算出哈希值。 二.加密哈希函数的三个特性 1.collision-resistance(碰撞阻力&#x…

数学建模两篇小文

1.雪球的融化 设雪球在融化时体积的变化率与表面积成比例&#xff0c;并且在融化过程中它始终为球体。该雪球在开始时的半径为6cm&#xff0c;经过2h后&#xff0c;其半径缩小为3cm。求雪球的体积随时间变化的关系。 解 ~~~~~ 设 t t t时刻雪球的体积为 V ( t ) V(t) V(t)&am…

ET中发送Get请求和Post请求(C#)

应用场景&#xff1a;一个游戏可能会衍生出其他APP或小程序之类的软件&#xff0c;例如王者营地是王者荣耀的官方APP&#xff0c;王者营地提供资讯、赛事、社区、战绩等功能。所以游戏端会和衍生出来的软件端做一些数据互通。这里把软件端称为中台系统。 Get请求和Post请求的区…

华为:数字化转型只有“起点”,没有“终点”

上个月&#xff0c;我收到了一位朋友的私信&#xff0c;他询问我是否有关于华为数字化转型的资料。幸运的是&#xff0c;我手头正好收藏了一些&#xff0c;于是我便分享给他。 然后在昨天&#xff0c;他又再次联系我&#xff0c;并感慨&#xff1a;“如果当初我在进行企业数字…

活着就好20241226

亲爱的朋友们&#xff0c;大家早上好&#xff01;&#x1f31e; 今天是26号&#xff0c;星期四&#xff0c;2024年12月的第二十六天&#xff0c;同时也是第51周的第四天&#xff0c;农历甲辰[龙]年十一月初二十二日。在这晨光熹微的美好时刻&#xff0c;愿那和煦而明媚的阳光继…

Android基于Path的addRoundRect,Canvas剪切clipPath简洁的圆形图实现,Kotlin(2)

Android基于Path的addRoundRect&#xff0c;Canvas剪切clipPath简洁的圆形图实现&#xff0c;Kotlin&#xff08;2&#xff09; import android.content.Context import android.graphics.BitmapFactory import android.graphics.Canvas import android.graphics.Path import a…

中化信息与枫清科技深化合作:共探“AI+”产业新生态

随着数字化转型的浪潮席卷全球&#xff0c;数据已成为推动创新和经济增长的关键力量。为持续深化数据要素价值挖掘与应用实践&#xff0c;推动打造行业交流平台&#xff0c;驱动产业创新共荣&#xff0c;2024 年 12 月 18 日 -19 日&#xff0c;由中国通信标准化协会主办的“20…

Flink Data Source详解

注意在高版本中SourceFunction以及其子类RichSourceFunction、ParallelSourceFunction等已经被标记为废弃,所以我们要看数据源的实现只需要关注Source接口(org.apache.flink.api.connector.source.Source)。了解Source背后的架构和运行原理有助于我们更好的使用Source,或者…