Linux 多线程同步机制(上)
文章目录
- 前言
- 一、线程同步
- 二、互斥量 mutex
- 三、死锁
- 总结
前言
一、线程同步
在多线程环境下,多个线程可以并发地执行,访问共享资源(如内存变量、文件、网络连接 等)。
这可能导致 数据不一致性, 死锁, 竞争条件等 问题。
为了解决这些问题,需要使用同步机制来确保线程间的协作和互斥访问共享资源。
“同步” 的目的 是为了避免数据的混乱,解决与时间有关的错误。实际上,不仅线程需要同步,进程间,信号间等等都需要同步机制。
线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时 其他线程为保证数据的一致性,不能调用该功能。
二、互斥量 mutex
互斥锁(Mutex,全称为 Mutual Exclusion)是一种常用的同步机制,用于保护共享资源免受多个线程同时访问和修改的影响。互斥锁提供了一种互斥访问的机制,同一时间只允许一个线程获取锁并访问被保护的资源。
每个线程在对资源操作前都尝试进行先加锁,成功加锁才能操作,操作结束解锁。
资源还是共享的,线程也还是竞争的。
但 通过 “锁” 就将资源的访问变成互斥操作,而后与时间有关的错误也就不会再产生了。
1. 互斥锁的基本操作包括两个关键操作:
-
加锁(Lock):线程通过申请互斥锁来获取对共享资源的访问权。如果互斥锁当前未被其他线程获取,线程成功获得锁然后进入临界区(Critical Section),可以访问共享资源。如果互斥锁已经被其他线程获取,申请锁的线程将被阻塞,直到锁被释放。
-
解锁(Unlock):线程在完成对共享资源的访问之后,释放互斥锁,使得其他线程可以申请并获取锁。
2. 互斥锁的主要应用函数 :
pthread_mutex_init: 用于初始化互斥锁变量。
pthread_mutex_destroy: 用于销毁互斥锁对象。
pthread_mutex_lock: 用于加锁,如果互斥锁已被其他线程占用,则当前线程阻塞。
pthread_mutex_trylock: 尝试加锁,如果互斥锁已被其他线程占用,则返回一个失败状态而不阻塞线程。
pthread_mutex_unlock: 用于解锁,释放互斥锁使其他线程可以获取。
3. 初始化线程锁 :
有两种方式可以对互斥锁进行初始化:静态初始化和动态初始化。
- 静态初始化: 是在定义互斥锁变量时直接进行初始化,不需要调用特定的初始化函数。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
PTHREAD_MUTEX_INITIALIZER 是一个宏,用于静态初始化互斥锁变量。 - 动态初始化:动态初始化是在运行时使用初始化函数对互斥锁进行初始化。
pthread_mutex_init(&mutex, NULL);
4. 示例代码:
在下面代码中,main 函数中有一个主线程 打印小写字母,my_thread 为 子线程 打印 大写字母。两个线程通过互斥锁来访问 共享资源。
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>pthread_mutex_t lock; // 创建 互斥锁void *my_thread(void *arg)
{srand(time(NULL)); // 设置随机种子while(1){pthread_mutex_lock(&lock);printf("ABC ");sleep(rand() % 3);printf("XYZ\n");pthread_mutex_unlock(&lock);sleep(rand() % 3); // 休眠随机秒,释放cpu资源}pthread_exit(NULL);
}int main(void)
{pthread_t tid;int ret;srand(time(NULL)); // 设置随机种子ret = pthread_mutex_init(&lock, NULL); // 初始化互斥锁if(ret != 0){printf("pthread_mutex_init err\n");}ret = pthread_create(&tid, NULL, my_thread, NULL);if(ret != 0){printf("pthread_create err\n");}while(1){pthread_mutex_lock(&lock);printf("abc ");sleep(rand() % 3);printf("xyz\n");pthread_mutex_unlock(&lock);sleep(rand() % 3);}pthread_mutex_destroy(&lock); // 销毁 互斥锁pthread_join(tid,NULL); // 等待回收线程,获取回收状态return 0;
}
注意 :
锁粒度(Lock Granularity):锁的粒度应该尽可能小,以避免锁定过长时间,从而降低了并发性能。
三、死锁
死锁产生的原因:死锁是指多个线程或进程因为彼此相互等待对方所持有的资源而无法继续执行的状态。
解决:
- 使用资源的有序性:通过规定线程获取资源的顺序,避免出现循环等待的情况。例如,可以约定所有线程按照一定的顺序获取资源,从而避免死锁的发生。
如果下面两个线程 获取资源的顺序是相反的,则可能会产生死锁。可以将 线程 B 先获取 m1锁,再获取 m2锁。

以下面代码的方式获取锁,不会存在死锁风险。
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;void *my_thread1(void *arg)
{pthread_mutex_lock(&lock1);printf("my_thread1 : begin\n");pthread_mutex_lock(&lock2);printf("my_thread1 : end\n");pthread_mutex_unlock(&lock2);pthread_mutex_unlock(&lock1);pthread_exit(NULL);
}void *my_thread2(void *arg)
{pthread_mutex_lock(&lock1);printf("my_thread2 : begin\n");pthread_mutex_lock(&lock2);printf("my_thread2 : end\n");pthread_mutex_unlock(&lock2);pthread_mutex_unlock(&lock1);pthread_exit(NULL);
}int main(void)
{pthread_t tid1,tid2;int ret;ret = pthread_create(&tid1, NULL, my_thread1, NULL);if(ret != 0){printf("pthread1_create err\n");}ret = pthread_create(&tid2, NULL, my_thread2, NULL);if(ret != 0){printf("pthread2_create err\n");}pthread_join(tid1,NULL);pthread_join(tid2,NULL);return 0;
}
- 设置超时机制:在请求资源时,设置一个超时时间,在超过该时间后如果仍未获得资源,则放弃等待,释放已经获取的资源,避免长时间的死锁等待。
总结
相关文章:
Linux 多线程同步机制(上)
文章目录 前言一、线程同步二、互斥量 mutex三、死锁总结 前言 一、线程同步 在多线程环境下,多个线程可以并发地执行,访问共享资源(如内存变量、文件、网络连接 等)。 这可能导致 数据不一致性, 死锁, 竞争条件等 问题。 为了解…...
C++学习vector
1,把list的相关函数都实现出来(未完) 2, 运行结果:...
17.3 【Linux】systemctl 针对 service 类型的配置文件
17.3.1 systemctl 配置文件相关目录简介 服务的管理是通过 systemd,而 systemd 的配置文件大部分放置于/usr/lib/systemd/system/ 目录内。但是 Red Hat 官方文件指出, 该目录的文件主要是原本软件所提供的设置,建议不要修改!而要…...
融云获评「创业邦 · 最具创新价值出海服务商」
点击报名,9 月 21 日融云直播课 8 月 22 日 - 23 日,创业邦主办的“2023 DEMO WORLD 全球开放式创新大会暨企业出海未来大会”在上海举行,会上发布了“创业邦 2023 出海企业创新价值 100 强”,融云荣登榜单,获评“最具…...
【中危】Apache XML Graphics Batik<1.17 存在SSRF漏洞 (CVE-2022-44729)
zhi.oscs1024.com 漏洞类型SSRF发现时间2023-08-23漏洞等级中危MPS编号MPS-2022-63578CVE编号CVE-2022-44729漏洞影响广度极小 漏洞危害 OSCS 描述Apache XML Graphics Batik 是一个开源的、用于处理可缩放矢量图形(SVG)格式图像的工具库。 受影响版本中࿰…...
AssemblyManager 程序集管理器
AssemblyManager 程序集管理器 程序执行中使用反射对框架的搭建有着强大的影响,如何管理程序集方便使用反射获取类型操作对象是本文章的重点 1.AssemblyInfo 对于一个程序集这里使用一个AssemblyInfo对象进行管理 Assembly :对应的程序集AssemblyTyp…...
几个nlp的小任务(生成式任务——语言模型(CLM与MLM))
@TOC 本章节需要用到的类库 微调任意Transformers模型(CLM因果语言模型、MLM遮蔽语言模型) CLM MLM 准备数据集 展示几个数据的结构...
单元测试用例mock的使用方法
单元测试用例mock的使用方法 提升代码测试覆盖率的关键策略 为什么单元测试是如此重要? 在软件开发中,单元测试是一个关键的环节,可以确保代码的质量和稳定性。而在进行单元测试时,使用mock对象可以帮助我们更好地测试代码逻辑…...
3D步进式漫游能够在哪些行业应用?
VR技术一直以来都是宣传展示领域中的热门话题,在VR全景技术的不断发展下,3D步进式漫游技术也逐渐覆盖各行各业,特别是在建筑、房产、博物馆、企业等领域应用更加广泛,用户通过这种技术能够获得更加直观、生动、详细的展示体验&…...
2023蓝帽杯初赛ctf部分题目
Web LovePHP 打开网站环境,发现显示出源码 来可以看到php版本是7.4.33 简单分析了下,主要是道反序列化的题其中发现get传入的参数里有_号是非法字符,如果直接传值传入my_secret.flag,会被php处理掉 绕过 _ 的方法 对于__可以…...
vue3+ts封装弹窗,分页封装
定义defaultDialog .vue <script lang"ts" setup> import { ref,toRefs,onUpdated } from vue import { ElMessageBox } from element-plus const props defineProps({//接收参数,父组件传的时候用:msg123的形式msg:String,show:{type:Boolean,defa…...
2023-08-30 数据库-并发控制-冲突可串行化调度-是否可串行化检测-优先图-分析
摘要: 将冲突进行可串行化调度, 是解决冲突是一个基本功能. 对于冲突是否可被串行化调度, 比较有效的就是优先图的方法. 本文对检测冲突可串行化调度的优先图做一些分析. 上下文参考: 2023-08-30 数据库-并发控制-冲突可串行化的调度-思考_财阀悟世的博客-CSDN博客 事务的基…...
人员着装识别算法 yolo
人员着装识别系统通过yolo网络模型识别算法,人员着装识别系统算法通过现场安装的摄像头识别工厂人员及工地人员是否按要求穿戴着装,实时监测人员的着装情况,并进行相关预警。目标检测架构分为两种,一种是two-stage,一种…...
Linux:权限
目录 一、shell运行原理 二、权限 1.权限的概念 2.文件访问权限的相关设置方法 三、常见的权限问题 1.目录权限 2.umsk(权限掩码) 3.粘滞位 一、shell运行原理 1.为什么我们不是直接访问操作系统? ”人“不善于直接使用操作系统如果让人直接访问操作系统&a…...
Unity记录4.3-存储-点击Tilemap保存或读取区块
文章首发见博客:https://mwhls.top/4816.html。 无图/格式错误/后续更新请见首发页。 更多更新请到mwhls.top查看 欢迎留言提问或批评建议,私信不回。 汇总:Unity 记录 摘要:点击tilemap,文件 保存/读取 该地图区块数据…...
【小吉测评】哔哩哔哩接入AI?!效果如何?
文章目录 🎄前言⭐申请方式🏳️🌈注意 🛸简介🍔上手体验🛸进行数学计算🥰可以写代码吗 🎄前言 最近人工智能特别火,chatgpt,Claude2,文心一言等…...
微信开发之一键踢出群聊的技术实现
简要描述: 删除群成员 请求URL: http://域名地址/deleteChatRoomMember 请求方式: POST 请求头Headers: Content-Type:application/jsonAuthorization:login接口返回 参数: 参数名必选…...
基于Spring Boot 的 Ext JS 应用框架之coworkee
Ext JS 官方提供了一个人员管理的完整应用框架 - coworkee。该框架的显示如下: 该框架的布局特点如下: 布局方式: 左右布局, 左侧导航栏默认收合特点:左侧导航区占用空间小, 工作区较大, 适合没有二级导航栏,工作区需要显示的内容较多的系统。如果导航栏是横向底部,就…...
HOT100打卡—day10—【DP+多维DP】—最新8.29(剩6题)
DP 1 70. 爬楼梯 70. 爬楼梯 一次做,AC代码: 疑问:怎么判断用搜索还是dp?这题,我没有受过dp训练所以第一反应是用dfs搜索,找到所有符合要求的叶子。 class Solution { public:int dp[50]; // step1&a…...
【不会用这个工具,你的Linux服务器就是个摆设!】
01 Tcpdump Tcpdump 是一个强大的网络监控工具,它允许用户有效地过滤网络上的数据包和流量。 这可以获得有关 TCP/IP 和网络上传输的数据包的详细信息。 当你遇到网络协议问题一筹莫展的时候,这时候往往可以通过tcpdump来看网络的通讯过程中发生了什么…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
