Linux线程同步

文章目录:

  • Linux线程同步
    • 条件变量
    • 同步概念与竟态条件
    • 条件变量函数
    • 为什么 pthread_cond_wait 需要互斥量?
    • 条件变量使用规范

Linux线程同步

条件变量

当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。例如一个线程访问队列时,队列为空,它就只能等待,直到其它线程将数据添加到队列中。在这种场景下就需要用到条件变量。

条件变量是一种线程间的同步机制,用于在一个线程等待某个条件满足时暂停执行,并在条件满足时被唤醒继续执行。

在上述示例中,可以使用条件变量来实现线程的等待和唤醒操作。当队列为空时,线程可以调用条件变量的等待函数,使线程进入等待状态,直到有其它线程向队列中添加了数据并通知条件变量,此时等待的线程就会被唤醒继续执行。

条件变量通常与互斥量一起使用,以确保线程在等待和唤醒时的安全性。在等待条件之前,线程需要先获取互斥锁,以确保在等待期间其它线程不会修改条件。而在唤醒之前,需要先释放锁,以允许其它线程获取锁并修改条件。

同步概念与竟态条件

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

在一般情况下,锁是不保证公平性的。若某个线程的优先级高,竞争资源的能力强,每次都能申请到锁,那么其它线程可能长时间竞争不到锁,导致饥饿问题。为了解决该问题,可以引入锁的公平性机制,即一个线程释放资源后,下一个获得锁的线程一定是等待时间最长的线程,这样就可以有效的避免某个线程一直占用锁而导致其它线程长时间等待。✨

示例:假设某个银行的柜台每次只能服务一个客户,而银行希望根据用户到来的先后顺序提供服务,在没有公平性的前提下,某些客户可能一直占用柜台,导致其它客户长时间等待。因此,为了确保公平性,银行引入了一个排队叫号系统,当一个客户到达银行之后,首先需要申请排队号码。当柜台空闲时,下一个序号的客户就会被叫到柜台执行任务。🎃

在该示例中,序号就是资源等待队列,柜台就是临界资源,而每个客户就是一个线程。通过引入排队叫号系统,可以让每个用户按照某种次序来获得相应的临界资源。

条件变量函数

初始化

函数 pthread_cond_init 用于初始化条件变量。它的函数定义如下:

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
// cond:要初始化的条件变量
// attr:条件变量的属性,可以传入NULL,表示使用默认属性

注意:使用 PTHREAD_COND_INITIALIZER 初始化的条件变量不需要进行手动销毁。

销毁

函数 pthread_cond_destroy 函数用于销毁条件变量,释放相关资源。在不需要使用条件变量时,应该调用该函数进行清理。它的函数定义如下:

int pthread_cond_destroy(pthread_cond_t *cond)
// cond:要销毁的条件变量

等待条件满足

函数 pthread_cond_wait 用于使线程等待条件变量的信号。在调用该函数前,需要先获取互斥锁,然后在函数内部自动释放互斥锁并等待条件变量的信号。它的函数定义如下:

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
// cond:需要在这个条件变量上进行等待
// mutex:与条件变量关联的互斥锁

唤醒等待

函数 pthread_cond_broadcast 用于发送广播信号,唤醒所有等待该条件变量的线程。pthread_cond_signal 函数用于发送信号,唤醒一个等待该条件变量的线程。它们的函数定义如下:

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
// cond:要发送信号的条件变量

示例:代码实现了一个多线程程序,其中定义了一个条件变量 cond 和一个互斥锁 mutex ,以及一个全局退出变量 quit 。程序的功能是允许用户输入命令,如果输入的命令是 “c”,则通过调用pthread_cond_broadcast(&cond) 广播条件变量的信号,唤醒所有等待在条件变量上的线程。如果输入的命令是 “q” ,则设置全局退出变量 quittrue ,并跳出循环,使程序退出。

#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;

// 定义一个条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 定义一个互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 当前用不上,但是接口需要
// 定义一个全局退出变量
volatile bool quit = false;

void *waitCommand(void *args)
{
    pthread_detach(pthread_self());
    while (!quit)
    {
        // 执行了下面的代码,证明某一种条件不就绪,需要该线程进行等待
        // 三个线程,都会在条件变量下进行排队等待
        pthread_cond_wait(&cond, &mutex); // 让对应的线程进行等待,等待被唤醒
        cout << "thread id : " << pthread_self() << " run..." << endl;
    }
}

int main()
{
    pthread_t t1, t2, t3;
    pthread_create(&t1, nullptr, waitCommand, nullptr);
    pthread_create(&t2, nullptr, waitCommand, nullptr);
    pthread_create(&t3, nullptr, waitCommand, nullptr);

    while (true)
    {
        char n;
        cout << "请输入你的command(c/q): ";
        cin >> n;
        if (n == 'c')
            pthread_cond_broadcast(&cond);
        else
        {
            quit = true;
            break;
        }

        usleep(1000);
    }
    pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    return 0;
}

运行程序,结果如下:

在这里插入图片描述

当输入 “c” 的时候,所有在该条件变量下等待的线程被唤醒执行任务;当输入 “q” 时,线程退出。

为什么 pthread_cond_wait 需要互斥量?

  • 条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所有必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且友好的通知等待在条件变量上的线程。
  • 条件变量不会无缘无故的突然变得满足了,必然会牵扯到共享数据的变化。所以一定要用互斥锁来保护。没有互斥锁就无法安全的获取和修改共享数据。
    在这里插入图片描述
  • 线程在进入临界区之前,需要先获取互斥锁。然后判断条件是否满足,如果条件不满足,则调用 pthread_cond_wait 函数进入等待状态,在进入等待状态之前,pthread_cond_wait 函数会自动释放互斥锁,允许其它线程获取互斥锁并修改共享数据。
  • 当其它线程修改了共享数据,并调用 pthread_cond_signalpthread_cond_broadcast 函数发送条件变量的信号时,在条件变量上等待的线程会被唤醒。
  • 被唤醒的线程会重新获取互斥锁,并检查条件是否满足。如果条件满足,线程会继续执行后续的操作;如果条件不满足,线程也会继续等待。
  • 最后,线程完成了对共享数据的操作后,会释放互斥锁,让其它线程也可以继续访问该共享数据。

一个错误的设计

按照上面的说法,当进入临界区时,先上锁,发现条件不满足,就进行解锁,然后在该条件变量下进行等待。如下代码:

// 错误的设计
pthread_mutex_lock(&mutex);
while (condition_is_false) {
	pthread_mutex_unlock(&mutex);
	//解锁之后,等待之前,条件可能已经满足,信号已经发出,但是该信号可能被错过
	pthread_cond_wait(&cond);
	pthread_mutex_lock(&mutex);
}
pthread_mutex_unlock(&mutex);
  • 由于解锁和等待不是原子操作。调用解锁之后,pthread_cond_wait 之前,如果已经有其它线程获取到互斥量,摒弃条件满足,发送了信号,那么 pthread_cond_wait 将错过这个信号,可能会导致线程永远阻塞在这个 pthread_cond_wait 。所以解锁和等待必须是一个原子操作。
  • int pthread_cond_wait(pthread_cond_ t *cond,pthread_mutex_ t * mutex); 进入该函数后,会去看条件是否等于0?若等于0,则说明不满足条件,此时会先将对应的互斥锁解锁,直到 pthread_cond_wait 函数返回时再将条件变量该为1,并给对应的互斥量加锁。

条件变量使用规范

等待条件代码

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.mfbz.cn/a/125644.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity 实现文字过长显示省略号

为了整体效果&#xff0c;当文字过长时&#xff0c;我们就会把超出范围的文字弄成省略号。 要实现文字过长显示省略号&#xff0c;只需要使用TextMeshPro&#xff0c;并设置Overflow属性为Ellipsis即可。 如下图&#xff1a; 记。

【Proteus仿真】【Arduino单片机】LCD1602-IIC液晶显示

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用PCF8574、LCD1602液晶等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602液晶显示各种效果。 二、软件设计 /* 作者&#xff1a;嗨小…

SpringBootWeb案例——Tlias智能学习辅助系统(2)

前一节已经实现了员工信息的条件分页查询以及删除操作。 这一节继续完成新增员工、文件上传、修改员工、配置文件的功能。 目录 新增员工文件上传简介本地存储阿里云OSS介绍与入门项目集成阿里云(难点) 修改员工查询回显修改员工 配置文件参数配置化(Value)yml配置文件Configur…

Git安装配置保姆级教程和Git创建仓库的基本原理和常用命令

目录 前言 一、Git简介 1.Git 与 SVN 区别点 2.Git的介绍 3.Git 工作流程 4.Git 工作区、暂存区和版本库 二、Git安装配置 1.Linux 平台上安装 2.Windows 平台上安装 三、Git 创建仓库和下载 1、首先需要注册一个gitee账号 2.git初始化并提交到远程仓库 3.另一用户…

蓝桥杯每日一题2023.11.9

包子凑数 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 对于此题是一个简单DP的翻版问题&#xff0c;若能凑出当前的包子数&#xff0c;则凑出之前一定为dp[i - a[j]]&#xff0c;若表示出的dp[i]不是0则说明是一定存在数可以被凑出的&#xff0c;由题意&#xff1a;若凑不出的…

汽车工业生产线数字孪生可视化管理平台,赋予工厂车间数字化智慧化管理

在工业4.0 的时代背景下&#xff0c;随着企业数字化进程的推进&#xff0c;数字孪生可视化技术逐渐在汽车行业得到广泛应用&#xff0c;数字孪生智慧工厂的建设也成为了汽车行业数字化转型的趋势之一。汽车制造业属于典型的离散制造行业&#xff0c;汽车生产包含冲压、焊接、涂…

微机原理3

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案。 1. 在机器数中&#xff0c;零的表示形式唯一的编码是() A. 原码 B. 补码 C.移码 D. 反码 2,用于定义常数、变量的内存空间分配和定位的是()。 A. 伪指令 B.机器指令…

【Python】数据分析案例:世界杯数据可视化

文章目录 前期数据准备导入数据 分析&#xff1a;世界杯中各队赢得的比赛数分析&#xff1a;先打或后打的比赛获胜次数分析&#xff1a;世界杯中的抛硬币决策分析&#xff1a;2022年T20世界杯的最高得分者分析&#xff1a;世界杯比赛最佳球员奖分析&#xff1a;最适合先击球或追…

VM17虚拟机设置网络,本地使用工具连接虚拟机

VM17虚拟机设置网络&#xff0c;本地使用工具连接虚拟机 下载及安装虚拟机不再说明&#xff0c;网络一堆教程。此处只对VM17设置网路及本地使用工具连接虚拟机操作&#xff0c;进行说明。 我下载的是VM17&#xff0c;网上有说VM16是较稳定的版本。想尝尝鲜&#xff0c;结果耗…

debian 已安装命令找不到 解决方法

前言&#xff1a;安装了debian系统&#xff0c;更新完软件包安装软件之后发现很多命令找不到&#xff0c;查找命令路径发现命令已经安装了&#xff0c;但是没办法直接使用 更新软件包 &#xff08;第一次安装的系统一定要执行&#xff0c;不然可能无法安装软件&#xff09; apt…

leetcode:762. 二进制表示中质数个计算置位(python3解法)

难度&#xff1a;简单 给你两个整数 left 和 right &#xff0c;在闭区间 [left, right] 范围内&#xff0c;统计并返回 计算置位位数为质数 的整数个数。 计算置位位数 就是二进制表示中 1 的个数。 例如&#xff0c; 21 的二进制表示 10101 有 3 个计算置位。 示例 1&#xf…

简单好看个人引导页毛玻璃页面 HTML 源码

毛玻璃个人引导页源码&#xff0c;界面简洁&#xff0c;已测可完美搭建&#xff0c;UI非常不错的&#xff0c;有兴趣的自行去安装体验吧&#xff0c;其它就没什么好介绍的了。 学习资料源代码&#xff1a;百度网盘 请输入提取码&#xff1a;ig8c

微信小程序将后端返回的图片文件流解析显示到页面

说明 由于请求接口后端返回的图片格式不是一个完整的url,也不是其他直接能显示的图片格式&#xff0c;是一张图片 后端根据模板与二维码生成图片,返回二进制数据 返回为文件流的格式,用wx.request请求的时候&#xff0c;就自动解码成为了下面这样的数据数据格式,这样的数据没…

Window环境NFS服务务器搭建及连接

1.NFS服务端搭建&#xff0c; 下载haneWIN NFS 服务端软件&#xff08;工具下载路径&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1HXeQ8nIY4RHVltd0uAvFaw 提取码&#xff1a;w18j &#xff09; 2.安装haneWIN NFS 服务端软件比较简单&#xff0c;直接点下一步即可…

怎么将pdf转换成word?

怎么将pdf转换成word&#xff1f;将pdf文件转换成word是一件非常重要的转换技能&#xff0c;将pdf转换成word可以解决非常多的问题&#xff0c;总结起来主要有以下这些&#xff1a;编辑文本&#xff1a;① PDF文件通常是不可编辑的&#xff0c;而将其转换为Word格式后&#xff…

c#数据类型

常量 /*常量是固定的量&#xff0c;在运行过程中不可以改变的量 const 来修饰不能改变的量*/ // public private protected internal 是访问修饰符using System.Security.Cryptography.X509Certificates;namespace ConsoleApp1 {internal class Program{public const int a 1…

Semantic-Guided Zero-Shot Learning for Low-Light ImageVideo Enhancement

论文阅读之无监督低光照图像增强 Semantic-Guided Zero-Shot Learning for Low-Light Image/Video Enhancement 代码&#xff1a; https://github.com/ShenZheng2000/SemantiGuided-Low-Light-Image-Enhancement 在低光条件下增加亮度的一个可行方法是使用更高的ISO或更长时间…

qt-C++笔记之Qt中的时间与定时器

qt-C笔记之Qt中的时间与定时器 code review! 文章目录 qt-C笔记之Qt中的时间与定时器一.Qt中的日期时间数据1.1.QTime&#xff1a;获取当前时间1.2.QDate&#xff1a;获取当前日期1.3.QDateTime&#xff1a;获取当前日期和时间1.4.QTime类详解1.5.QDate类详解1.6..QDateTime类…

IP可视对讲实时录制系统

介绍 软件架构 技术支持 CallRecored介绍 IP可视对讲实时录制系统设计了数据库表&#xff0c;并完成了数据库建模&#xff0c;采用了视频编解码技术&#xff0c;高效网络传输&#xff0c;磁盘高效读写技术&#xff0c;以及提供开放接口。 系统客户端采用扁平化UI&#xff0c;…

如何设计vue项目的权限管理?

权限管理的重要性及必要性 数据安全&#xff1a;权限管理可以确保只有具有相应权限的用户能够访问和操作特定的数据。这可以保护敏感数据不被未授权的用户访问&#xff0c;从而提高数据的安全性。功能控制&#xff1a;权限管理可以根据用户的角色和权限设置&#xff0c;控制用户…
最新文章