【多线程】线程同步--条件变量的原理及其使用

文章目录

  • 前言
  • 线程同步的基本概念
    • 条件变量
      • 定义条件变量
      • 初始化条件变量
      • 销毁条件变量
      • 等待条件(重要)
      • 唤醒等待
      • 简单运用
      • 常见使用条件变量的格式

前言

线程同步意味着在多线程并发执行中,协调线程之间的执行顺序,以确保共享资源被正确访问和修改。线程同步的维护本质就是在安排线程之间的执行顺序。那么在linux中是如何维护线程同步的呢?本篇文章将围绕这个为题展开叙述。

线程同步的基本概念

下面介绍一些有关线程同步的基本概念。

条件变量

当一个线程互斥的访问某个变量,即访问临界资源时给临界区上互斥锁,这个时候其它线程只能等待。那什么时候其它线程可以继续申请临界资源呢?我们希望当一个线程使用完临界资源后,正在等待的线程能够知道这一事件的发生从而重新申请资源,而不是一直重复申请这个动作

就像一个闹钟,当闹钟响了之后我们就知道该起床了,而不是睡一下又看下时间。

条件变量提供一种线程通信的方法,使得一个线程可以等待另一个线程满足某种条件后再继续执行。具体的,我们将这种通知一个线程继续执行的动作称为唤醒

于是,借助条件变量,我们就能实现协调线程之间访问临时资源的顺序性。

同时线程库给我们提供了一些接口用来操作条件变量,下面介绍一些常见的关于条件变量的操作。(头文件都是pthread.h

定义条件变量

初始化条件变量

  1. 动态初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); 
  • cond :要初始化的条件变量
  • attr:条件变量的属性,通常是NULL
  1. 静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

销毁条件变量

int pthread_cond_destroy(pthread_cond_t *cond);

销毁某个条件变量,成功返回0,失败返回错误代码
在这里插入图片描述

等待条件(重要)

如果当前线程没有申请到临界资源,该线程可以选择等待。

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

在调用该函数时,互斥锁mutex必须被锁住,并等待唤醒。唤醒之后线程重新锁住互斥锁并继续执行。值得注意的是,pthread_cond_wait函数首先会解锁与之关联的互斥锁mutex,这也是为什么使用该函数时mutex必须是被锁住的。然后调用该函数的线程进入阻塞状态,直到被唤醒。最后,条件变量被通知之后,pthread_cond_wait重新锁定互斥锁mutex
对于该函数提出以下问题:

  • 为什么要在pthread_cond_wait中传入互斥锁
    • 在调用 pthread_cond_wait 时,互斥锁是已经锁住的,确保没有其他线程可以修改共享资源。
    • pthread_cond_wait 在进入等待状态之前会自动释放互斥锁,使得其他线程可以修改条件。
    • 当线程被唤醒后,pthread_cond_wait 会重新获得互斥锁,然后再继续执行,因为此时还在临界区,还会访问临界资源。

唤醒等待

  1. 唤醒某个线程
int pthread_cond_signal(pthread_cond_t *cond);

唤醒一个等待在条件变量 cond 上的线程。如果有多个线程在等待条件变量,具体唤醒哪一个线程是不确定的。
成功返回0,失败则返回错误码

  1. 唤醒所有正在等待该条件变量的线程
int pthread_cond_broadcast(pthread_cond_t *cond);

唤醒所有等待在条件变量 cond 上的线程。同样成功返回0,失败则返回错误码。

简单运用

下面我们使用条件变量和互斥锁来设计一个简单的代码样例

#include <iostream>
#include <unistd.h>
#include <pthread.h>using namespace std;pthread_cond_t cond;
pthread_mutex_t mutex;void *r1(void *arg) // 等待函数,执行该函数的线程一直处于while (true)
{pthread_cond_wait(&cond, &mutex);cout << "被唤醒" << endl;return arg;
}void *r2(void *arg) // 唤醒函数,执行该函数的线程一直尝试唤醒某个等待的线程
{while (true){pthread_cond_signal(&cond);cout << "唤醒某个线程" << endl;sleep(1);}
}int main()
{pthread_t t1, t2; // 定义两个线程pthread_cond_init(&cond, NULL);   // 初始化条件变量pthread_mutex_init(&mutex, NULL); // 初始化互斥锁pthread_create(&t1, NULL, r1, NULL); // 创建线程并分配执行函数pthread_create(&t1, NULL, r2, NULL);pthread_join(t1, NULL); // 等待线程退出pthread_join(t2, NULL);pthread_mutex_destroy(&mutex); // 销毁互斥锁和条件变量pthread_cond_destroy(&cond);return 0;
}

在这里插入图片描述

常见使用条件变量的格式

  • 等待条件代码:
pthread_mutex_lock(&mutex); while (条件为假) //不满足条件陷入等待,在循环中等待是为了防止伪唤醒pthread_cond_wait(cond, mutex); 
// ...
// 访问临界资源//...pthread_mutex_unlock(&mutex); 
  • 给条件发送信号,即可以唤醒等待条件中的线程
pthread_mutex_lock(&mutex); 设置条件为真 pthread_cond_signal(cond); //唤醒某个线程pthread_mutex_unlock(&mutex); 

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

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

相关文章

Kylin系列(三)安装与配置:搭建你的第一个 Kylin 环境

目录 1. Kylin 简介 1.1 Kylin的核心特点 1.2 适用场景 2. 环境准备 2.1 硬件要求 2.2 软件依赖 3. 安装与配置 3.1 安装JDK 3.2 安装Hadoop 3.2.1 下载并解压Hadoop 3.2.2 配置Hadoop环境变量 3.2.3 配置Hadoop文件 3.2.4 格式化HDFS并启动Hadoop服务 3.3 安装H…

hive架构详解:HQL案例解析(第15天)

系列文章目录 一、Hive基础架构&#xff08;重点&#xff09; 二、Hive数据库,表操作&#xff08;重点&#xff09; 三、Hadoop架构详解(hdfs)&#xff08;补充&#xff09; 四、Hive环境准备&#xff08;操作&#xff09;(补充) 文章目录 系列文章目录前言一、Hive基础架构1、…

4. 小迪安全v2023笔记 javaEE应用

4. 小迪安全v2023笔记 javaEE应用 ​ 大体上跟随小迪安全的课程&#xff0c;本意是记录自己的学习历程&#xff0c;不能说是完全原创吧&#xff0c;大家可以关注一下小迪安全。 若有冒犯&#xff0c;麻烦私信移除。 默认有java基础。 文章目录 4. 小迪安全v2023笔记 javaEE应…

分块

分块 分块是将线段树的懒标记方法一般化&#xff0c;可证明通常情况下以 n \sqrt n n ​分块是最优解。 分块思想核心&#xff1a; 整块打包维护 碎块逐个枚举 int len,num;//len:每块长度,num:分块数量 int begin[],end[],pos[],sum[],add[];//begin,end:每块的始末下标 po…

linux下安装cutecom串口助手;centos安装cutecom串口助手;rpm安装包安装cutecom串口助手

在支持apt-get的系统下安装 在终端命令行中输入&#xff1a; sudo apt-get install cutecom 安装好后输入 sudo cutecom 就可以了 关于如何使用&#xff0c;可以看这个https://www.cnblogs.com/xingboy/p/14388610.html 如果你的电脑不支持apt-get。 那我们就通过安装包…

‘wget‘ 不是内部或外部命令,也不是可运行的程序

在Windows环境下创建了虚拟环境并安装了wget包&#xff0c;但在使用该命令的时候仍然报错&#xff0c;‘wget’ 不是内部或外部命令,也不是可运行的程序 解决方案&#xff1a; 去官网下载对应位数的.exe文件&#xff0c;将其放在C:\Windows\System32目录下即可, 别下错版本&a…

宝塔面板部署Flask项目教程(最新版)

本教程适用于最新版的宝塔&#xff01;&#xff01;&#xff01; 本教程适用于最新版的宝塔&#xff01;&#xff01;&#xff01; 本教程适用于最新版的宝塔&#xff01;&#xff01;&#xff01; 1 准备 1.1 依赖文件 在你的项目根目录下生成一个依赖文件&#xff0c;执行…

美业收银系统怎么选?哪些功能实用?美业门店管理系统|拓客系统

选择美业会员系统时&#xff0c;你可以考虑以下几个方面的功能来确定哪些对你最实用&#xff1a; 1.会员管理&#xff1a; 系统应该能够轻松管理会员资料、积分、消费记录等信息&#xff0c;以便更好地了解客户需求并提供个性化服务。 2.促销与营销工具&#xff1a; 包括发…

Perl中追踪文件脉动:文件系统事件通知机制全解析

&#x1f4e1; Perl中追踪文件脉动&#xff1a;文件系统事件通知机制全解析 在Perl编程中&#xff0c;文件系统事件通知机制允许程序响应文件或目录的变化&#xff0c;例如文件的创建、删除、修改等。这种机制对于实现如文件监控、数据同步、自动化任务等应用至关重要。本文将…

电商开通云账户分账系统实现功能场景

什么是虚拟银行账户: 银行虚拟户也称为银行虚拟公户&#xff0c;是指企业或机构在银行开设的一种特殊类型的银行账户。它与普通银行账户不同&#xff0c;虚拟公户通常不涉及实际的资金流动&#xff0c;而主要用于管理和监控资金流向&#xff0c;以及实现特定的业务和财务目标。…

vue3项目安装和使用element-plus

第一步&#xff1a;安装 npm install element-plus --save 第二步&#xff1a;在main.js文件夹上引入 import { createApp } from vue import ./style.css import ElementPlus from element-plus import element-plus/dist/index.css import App from ./App.vueconst app c…

3D云渲染工具对决:Maya与Blender的性能和功能深度比较

3D建模和动画制作已成为数字领域不可或缺的一环&#xff0c;无论是在影视特效的震撼场面&#xff0c;还是在游戏角色的生动表现&#xff0c;3D技术都扮演着至关重要的角色。而在这一领域&#xff0c;Maya和Blender这两款软件&#xff0c;以其强大的功能和广泛的应用&#xff0c…

【JavaEE】进程

目录 一.冯诺依曼体系结构 二.CPU的核心概念 核心数 频率&#xff08;Clock Speed 或时钟频率&#xff09; 如何选择合适的CPU 三.指令的执行 1.什么是指令 1.取指令 2.解析指令 3.执行指令 4.访问内存&#xff08;Memory&#xff09;: 5.写回结果&#xff08;Write…

视频解码故障案例两则

案例1 绿边 故障分析&#xff1a; 这个能明显看到视频上方出现绿色半透明边带。这说明Y数据正常。UV数据不正常。 它显然与视频帧的垂直分辨率设置有关。 UV数据和Y数据是连续放置的&#xff0c;如果上方出现彩色数据失调&#xff0c;说明这部分数据实际仍然是Y数据。也就是…

为什么我在go语言里从前端接收到的参数是数字28546.123456,但是我不能使用float32只能使用float64呢?

在 Go 语言中&#xff0c;当你从前端&#xff08;例如通过 HTTP 请求&#xff09;接收数据时&#xff0c;这些数据通常以字符串的形式到达后端。然后&#xff0c;后端需要将这些字符串解析或转换为适当的类型&#xff0c;比如 float32 或 float64。 然而&#xff0c;如果你发现…

JAVASE进阶day08(Map双列集合)

HashMap 1.HashMap基本使用 package com.lu.day08.map;import java.util.HashMap; import java.util.Map; import java.util.Set;public class MapDome {public static void main(String[] args) {HashMap<String , String> map new HashMap<>();//添加后者修改-…

H264视频编码中Annex B 格式介绍

Annex B 格式是 H.264 (也称为 AVC) 视频编码标准中的一种数据表示格式&#xff0c;用于将视频数据从编码器传输到解码器。它主要用于流媒体传输和文件存储。 文章目录 Annex B 格式的定义Annex B 格式的主要特点Annex B 与其他格式的对比Annex B 格式示例将 H.264 数据从 MP4…

查询(q_proj)、键(k_proj)和值(v_proj)投影具体含义

查询(q_proj)、键(k_proj)和值(v_proj)投影&#xff0c;这些投影是自注意力机制的核心组件&#xff0c;特别是在Transformer架构中。 让我们通过一个简化的例子来说明&#xff1a; import numpy as np# 假设输入维度是4&#xff0c;注意力头数是2 input_dim 4 num_heads 2 …

每天一道Java面试题系列之--Spring如何解决循环依赖问题

面试题&#xff1a;Spring如何解决循环依赖问题&#xff1f; 问题背景&#xff1a; 在Spring框架中&#xff0c;循环依赖通常发生在单例&#xff08;Singleton&#xff09;作用域的bean之间。当两个或多个bean在它们的构造函数中相互引用时&#xff0c;Spring容器在创建这些b…

电脑32位和62位是什么意思

在现代计算机世界中&#xff0c;32位和64位是两个常见的术语&#xff0c;但许多用户可能不太清楚它们的确切含义以及它们之间的区别。本文将详细介绍32位和64位计算机的基本概念、如何查看您的计算机是32位还是64位&#xff0c;以及它们对用户的实际影响。 32位与64位的基本概…