Linux 线程同步

前言

上一期我们介绍了线程互斥,并通过加锁解决了多线程并发访问下的数据不一致问题!本期我们来介绍一下同步问题!

目录

前言

一、线程同步

• 线程同步的引入

• 同步的概念

理解同步和饥饿问题

• 条件变量

理解条件变量

• 同步的相关操作

条件变量的创建与销毁

等待条件

唤醒线程

简单的同步测试用例


一、线程同步

• 线程同步的引入

上一期加锁之后的抢票Demo中,我们发现虽然不会出现多卖出票的情况了,但是我么发现一个线程可以连续抢到很多的票,搞得我们有些线程像是黄牛了~!

上面某个线程一直执行抢票动作,而抢票的过程是互斥的,也就是加了锁的!在它抢票期间,其他的线程是一直得阻塞等待的,如果那些阻塞等待的线程一直竞争不到锁,就会造成线程长时间无法被调度的饥饿问题!为了解决上述的黄牛式的抢票的问题,让其他的线程有机会被调度!我们就引入了线程的同步~!

• 同步的概念

在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题的机制,叫做同步

竞态条件:因为时序问题而导致程序出现异常

理解同步和饥饿问题

OK,我们直接上一个例子解释:

话接上回,张三早上6:00就欢快的抢到VIP自习室的钥匙,进去自习了!过了一会,来了好多想要进VIP自习室自习的人!但是由于张三没出来,他们没有钥匙就进不去!

他们都在等着张三出来归还钥匙,但是张三不急不慢的自习到中午的12:00,此时他有点饿了,想出去吃个饭,出去吃饭就意味着仔细结束,得把钥匙归还!张三刚到门口把钥匙挂到门上,回头一看这么多等待的人,张三一想,我这把钥匙挂上去,吃个饭回来,我就是这些等待的人中的一个,又不知道到得等到啥时候~!所以张三心一横,又把钥匙拿了下来,又进去学习了;刚进去没几分钟张三就饿得不行了,于是去把钥匙挂到门上,回头一看这么多的人就又拿下来,强撑着进去了!就这样张三反复进出,直到晚上的8 : 00 ,张三自己不仅没有吃上饭、没专心的学习,而且还导致其他人也无法进入自习室学习!

但是按照规定张三并没有错,且符合自习室只允许持有钥匙的一人进入的规则!只不过他的这种行为极其不合理(现实中估计家人不保)!因为张三这种不合理的行为,导致了自习室的资源浪费,其他同学没机会进VIP自习室自习,从而陷入了 饥饿状态!为此,管理员连夜修改了规则:

• 在外面等待的同学必须排队等待

• 所有自习完的同学在归还玩钥匙之后,不能立即申请,下次申请,需要排队

新规则出来以后,自习室的使用都是按照一定的顺序进行申请使用,再也没有了以前的饥饿问题!上述的旧规则时期每张三反复进出的,导致其他人长时间不能进入自习室,就是导致饥饿问题!新规则后多人按照一定顺序申请使用自习室,就是同步


• 条件变量

原生的线程库 提供了 条件变量 来实现 线程同步

通过条件变量 -> 实现新线程同步 -> 解决了饥饿问题

 • 条件变量 :当一个线程互斥的访问某个变量时,他可能发现在其他线程改变状态之前,什么也做不了

比如当一个线程访问队列时,发现队列为空,它只能等待,直到其他线程往队列中添加数据,此时就可以考虑使用 条件变量

理解条件变量

现在有A和B两人协作的一个拿放苹果游戏

规则是A得蒙着眼睛,B不能说话!B向盘子放苹果,A从盘子拿苹果;盘子任意时刻只能由一人使用,最终哪个组拿的最多就获胜,奖励一个iphone16;

有很多组参加,你(李四)和你的搭档张三,想得第一名,整个iphone玩一玩!于是就报名参加了结果上半场,由于你不知道盘子是否有苹果而频繁的申请盘子,检测盘子;导致了你的搭档张三根本就无法拿到盘子,更别说放苹果了!所以,上半场以0个苹果结束!

在中场休息的时间,你很仔细阅读了规则,发现没说不能使用工具,所以,你俩就整了个铃铛,张三给你说,李四啊,你如果拿到盘子没有苹果,你就把盘子还回去,不要再拿了,你就定定的等着,当我把苹果放到盘子了,就敲响一声铃铛,你就来拿,你拿完继续等着!果然下半场,利用这个机制,你们拿下了很多的苹果!

但是,下半场结束后,有一组和你们的苹果数一样的多,所以有增加了一场,但是这一场的规则稍有变化,就是给每一组增加一位拿苹果的人,看最后哪一组拿的多,就谁赢!

有了上半场的经验,你和张三以及新队友王五,一起提前开会,你们说好了,由于多了一个人,这次铃铛的规则也变了,当敲一声时一个人来拿,当敲两声时,都来拿(但实际只有一个人能拿到盘子,所以两人得竞争,得拼手速)!于是就开始了,但这次显然你们比对手准备的好,你们最后比他们拿的多!

上述的盘子就是临界资源,一次只能一个人那盘子就是互斥铃铛就是条件变量!此时,当你的搭档不敲铃铛时,你啥也做不了,就在那等着!

条件变量的本质可以理解为 衡量或指示访问资源状态的一种机制

所以,条件变量内部必须实现两个东西:1、需要一个等待队列 2、需要一个通知机制!

• 同步的相关操作

条件变量的创建与销毁

条件变量互斥锁都是原生线程库中的,他的接口风格和互斥锁极其相似,例如:

互斥量的类型: pthread_mutex_t   条件变量的类型: pthread_cond_t

定义全局的条件变量

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

注意在全局创建条件变量时,初始化为 PTHREAD_COND_INITIALIZER自动销毁

定义局部的条件变量

#include <pthread.h>pthread_cond_t cond; // 定义一个条件变量
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

参数

restrict cond 表示要初始化的条条件变量

restrict attr 表示初始化时的相关属性,直接设置为nullptr即可

返回值

成功,返回0

失败,返回错误码

注意:这些接口的返回值都是一样的,后续不再介绍!

条件变量的销毁

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

参数

cond 表示要销毁的条件变量

等待条件

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

参数

cond :表示要等待的条件变量

restrict mutex :互斥锁,用于辅助的条件变量

为什么等待时需要一把互斥锁?

1、条件变量也是临界资源,也需要被保护

2、当条件不满足时,需要将线程挂起到特定的阻塞队列,但是其已持有锁资源,为了避免死锁,条件变量内部再把该线程挂起前,要对该锁资源进行释放,会用到它!

唤醒线程

当条件变量满足时,需要唤醒阻塞队列中等待该条件变量的线程,可以唤醒一个,也可以唤醒全部,这就是我们上述所说的通知机制!

#include <pthread.h>int pthread_cond_signal(pthread_cond_t *cond);//唤醒一个int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒所有

第一个表示唤醒等待条件变量阻塞队列的队头的那一个线程,第二个时唤醒阻塞队列中所有线程!

注意:当全部唤醒之后,所有的线程也会先去竞争锁,如果持有锁了继续后续的操作,如果竞争失败了,去锁那里等待锁资源!

简单的同步测试用例

我们写一个小Demo,让num个线程都在进入临界区之后等待,主线程唤醒之后再去执行!

#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>const int num = 5;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;    // 创建一个全局的条件变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 创建一个全局的互斥量void *Wait(void *args)
{const char *name = static_cast<char *>(args);while (true){// 加锁pthread_mutex_lock(&mutex);// 让所有线程一进来就再cond的条件下等待pthread_cond_wait(&cond, &mutex);std::cout << name << ", 正在运行....." << std::endl;// 解锁pthread_mutex_unlock(&mutex);}return nullptr;
}int main()
{pthread_t tid[num];// 启动5个线程for(int i = 0; i < num; i++){char* name = new char[128];snprintf(name, 128, "thread_%d", i+1);pthread_create(tid+i, nullptr, Wait, (void*)name);//创建5个线程}sleep(3);//d等所有的线程起来// 主线程唤醒新线程while(true){std::cout << "Main wake up new thread: " << std::endl;pthread_cond_signal(&cond);// 唤醒一个}// 等待线程for(int i = 0; i < num; i++){pthread_join(*(tid+i), nullptr);}return 0;
}

OK,此时是主线程一次唤醒一个线程,我们看看效果:

我们再来试试全部唤醒:

OK,没有问题!好兄弟我是cp我们下期再见!

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

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

相关文章

系列一、初始ElasticSearch

前言&#xff1a; 最近公司的业务有用到ElasticSearch&#xff0c;虽然说之前业余时间也自学过ElasticSearch技术&#xff0c;但是在公司实际的业务中开发中没有用过&#xff0c;再加上时间比较久远了&#xff0c;很多东西都忘记了&#xff0c;基于此我决定系统的重新学习一下这…

个人项目简单https服务配置

1.SSL简介 SSL证书是一种数字证书&#xff0c;由受信任的证书颁发机构&#xff08;CA&#xff09;颁发&#xff0c;用于在互联网通信中建立加密链接。SSL代表“安全套接层”&#xff0c;是用于在互联网上创建加密链接的协议。SSL证书的主要目的是确保数据传输的安全性和隐私性…

鸿蒙NEXT开发环境搭建(基于最新api12稳定版)

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

PMP--三模--解题--51-60

文章目录 14.敏捷--每日站会--内容--• 上次站会以来我都完成了什么&#xff1f;• 从现在到下一次站会&#xff0c;我计划完成什么&#xff1f;• 我的障碍&#xff08;或风险或问题&#xff09;是什么&#xff1f;--每日站会能够同步与协调相关的活动。14.敏捷--Scrum板 Scru…

【Ubuntu】VMware中虚拟网卡与服务器网卡的绑定

文章目录 服务器网卡和VMware中虚拟网卡的绑定1.在本机上查看需要的网卡名称2.服务器本机设置固定ip3.打开VMware后&#xff0c;将虚拟网卡与本机真实网卡进行绑定。4.给routeOS分配4张网卡&#xff0c;如图所示&#xff1a;5.ubuntu1和ubuntu2只需分配vmnet0和vmnet8即可&…

《More Effective C++》的学习

引用与指针 没有所谓的null reference reference一定需要代表某个对象&#xff0c;所以C要求reference必须有初值。 QString &s; 使用reference可能比使用pointer更高效。 因为reference一定是有效的&#xff0c;而指针可能为空&#xff08;需要多加一个判断&#xff0…

【PyTorch】图像目标检测

图像目标检测是什么 Object Detection 判断图像中目标的位置 目标检测两要素 分类&#xff1a;分类向量 [p0, …, pn]回归&#xff1a;回归边界框 [x1, y1, x2, y2] 模型如何完成目标检测 将3D张量映射到两个张量 分类张量&#xff1a;shape为 [N, c1]边界框张量&#xf…

索尼MDR-M1:超宽频的音频盛宴,打造沉浸式音乐体验

在音乐的世界里&#xff0c;每一次技术的突破都意味着全新的听觉体验。 索尼&#xff0c;作为音频技术的先锋&#xff0c;再次以其最新力作——MDR-M1封闭式监听耳机&#xff0c;引领了音乐界的新潮流。 这款耳机以其超宽频播放和卓越的隔音性能&#xff0c;为音乐爱好者和专…

深蕾半导体参加2024年度上海设计100+全球竞赛展览WDCC

展览介绍 WDCC2024 上海于2010年加入联合国教科文组织“创意城市网络”&#xff0c;定名为“设计之都”。“上海设计100”全球竞赛&#xff0c;遴选推广优秀设计案例&#xff0c;将“设计之都”的规划和愿景具体呈现。 ——展出时间、地点见文末—— 深蕾参展 深圳前海深蕾…

初识Linux · 进程等待

目录 前言&#xff1a; 进程等待是什么 为什么需要进程等待 进程等待都在做什么 前言&#xff1a; 通过上文的学习&#xff0c;我们了解了进程终止&#xff0c;知道终止是在干什么&#xff0c;终止的三种情况&#xff0c;以及有了退出码&#xff0c;错误码的概念&#xff…

Python | Leetcode Python题解之第448题找到所有数组中消失的数字

题目&#xff1a; 题解&#xff1a; class Solution:def findDisappearedNumbers(self, nums: List[int]) -> List[int]:n len(nums)for num in nums:x (num - 1) % nnums[x] nret [i 1 for i, num in enumerate(nums) if num < n]return ret

【RocketMQ】秒杀设计与实现

&#x1f3af; 导读&#xff1a;本文档详细探讨了高并发场景下的秒杀系统设计与优化策略&#xff0c;特别是如何在短时间内处理大量请求。文档分析了系统性能指标如QPS&#xff08;每秒查询率&#xff09;和TPS&#xff08;每秒事务数&#xff09;&#xff0c;并通过实例讲解了…

鸿蒙开发(NEXT/API 12)【申请接入Wear Engine服务】 穿戴服务

申请Wear Engine服务前&#xff08;开发者需实名认证为个人开发者或者企业开发者&#xff0c;认证前&#xff0c;请先了解二者的[权益区别] &#xff09;&#xff0c;确认开发环境并完成创建项目、创建HarmonyOS应用等基本准备工作&#xff0c;再继续进行以下开发活动。 进入华…

JVM(HotSpot):字符串常量池(StringTable)

文章目录 一、内存结构图二、案例讲解三、总结 一、内存结构图 JDK1.6 JDK1.8 我们发现&#xff0c;StringTable移入了Heap里面。所以&#xff0c;应该想到&#xff0c;StringTable将受到GC管理。 其实&#xff0c;1.6中&#xff0c;在方法区中的时候&#xff0c;也是受GC管…

Android Studio 新版本 Logcat 的使用详解

点击进入官方Logcat介绍 一个好的Android程序员要会使用AndroidStudio自带的Logcat查看日志&#xff0c;会Log定位也是查找程序bug的第一关键。同时Logcat是一个查看和处理日志消息的工具&#xff0c;它可以更快的帮助开发者调试应用程序。 步入正题&#xff0c;看图说话。 点…

Linux 之 IO模型

IO的本质是基于操作系统接口来控制底层的硬件之间数据传输&#xff0c;并且在操作系统中实现了多种不同的IO方式&#xff08;模型&#xff09;&#xff0c;比较常见的有下列三种 阻塞型IO模型 非阻塞型IO模型 多路复用IO模型 一、阻塞与非阻塞IO 一般默认的 IO 操作都是阻塞…

在Linux中进行OpenSSH升级(编译安装在openssh目录)

由于OpenSSH有严重漏洞&#xff0c;因此需要升级OpenSSH到最新版本。 注意&#xff1a;在OpenSSH升级过程中千万不要断开服务器连接&#xff0c;不然的话&#xff0c;会出现断开后连接不了服务器的情况。 第一步&#xff0c;查看当前的OpenSSH服务版本。 命令&#xff1a;ss…

DataEase v2 开源代码 Windows 从0到1环境搭建

一、环境准备 功能名称 描述 其它 操作系统 Windows 数据库 Mysql8.0 开发环境 JDK17以上 本项基于的21版本开发 Maven 3.9版本 开发工具 idea2024.2版本 前端 VSCode TIPS&#xff1a;如果你本地有jdk8版本&#xff0c;需要切换21版本&#xff0c;请看…

C语言 | Leetcode C语言题解之第448题找到所有数组中消失的数字

题目&#xff1a; 题解&#xff1a; int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize) {for (int i 0; i < numsSize; i) {int x (nums[i] - 1) % numsSize;nums[x] numsSize;}int* ret malloc(sizeof(int) * numsSize);*returnSize 0;for (in…

遥感图像文本检索

遥感图像文本检索是一种通过自然语言描述&#xff0c;从大量遥感图像中搜索与之相关的图像的技术。它用于遥感解释任务中&#xff0c;帮助用户根据文字描述快速找到符合条件的遥感图像&#xff0c;这在城市规划、环境监测、灾害管理等领域具有重要应用意义。 实现这一技术的核…