【Linux C | 多线程编程】线程同步 | 互斥量(互斥锁)介绍和使用
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰:
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、为什么需要互斥量
- 🎄三、互斥量的使用
- ✨3.1 互斥量的初始化
- ✨3.2 互斥量的销毁
- ✨3.3 互斥量的加锁和解锁
- 🎄四、互斥量的属性
- 🎄五、总结
![]()
🎄一、概述
互斥量采用的是英文mutual exclusive(互相排斥之意)的缩写,即mutex,是多线程编程中,常用来进行同步访问的方式之一。根据互斥量的用法,可以形象地将互斥量比喻成一把锁,锁住关键代码(临界区),每次只允许一个线程进入。
互斥量的工作机制:互斥量从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所以在该互斥锁上的阻塞线程都会变成可进行状态,第一个变成运行状态的线程可以对互斥量加锁,其他线程在次被阻塞,等待下次运行状态。
![]()
🎄二、为什么需要互斥量
大部分情况下, 线程使用的数据都是局部变量, 变量的地址在线程栈空间内, 这种情况下, 变量归属于单个线程, 其他线程无法获取到这种变量。但多数的多线程编程种,会出现一些资源是多个线程共享使用的,如:全局变量、堆空间指针变量等。
当多个线程可以同时改变某个共享资源,并且这个改变的操作不是原子操作,而又不加限制的话,那么改变的结果可能是意想不到的。这就是需要互斥量的原因。
🌰看例子:下面例子,创建4个线程,对共享资源(g_Count全局变量)执行了1000万次自加1操作。我们期待的结果应该是4000万,但运行结果有时却非4000万。
// 08_mutex_test.c
// gcc 08_mutex_test.c -lpthread
#include <stdio.h>
#include <pthread.h>
#include <sys/syscall.h>
int g_Count = 0;
void *func(void *arg)
{int i=0;for(i=0; i<10000000; i++){g_Count++;}return NULL;
}int main()
{// 创建4个线程pthread_t threadId[4];int i=0;for(i=0; i<4; i++){pthread_create(&threadId[i], NULL, func, NULL);}for(i=0; i<4; i++){pthread_join(threadId[i],NULL);printf("join threadId=%lx\n",threadId[i]);}printf("g_Count=%d\n",g_Count);return 0;
}
运行结果如下:执行三次,只出现了一次4000万,且每次结果都不一样。因为g_Count++;语句不是一个原子操作,假设4个线程同时获取到g_Count时值为1,4个线程都执行g_Count++后,每个线程都认为此时g_Count的值为2,但4个线程执行了4次了。

综上所述,当多个线程可以同时操作共享资源时,需要满足下面三点来使各个线程互斥:
1、当一个线程操作共享资源时,不允许其他线程同时操作该资源。
2、当线程不再操作共享资源时,不能阻碍其他线程操作该资源。
3、当多个线程同时操作一个共享资源时,只允许一个线程执行操作。
![]()
🎄三、互斥量的使用
正确地使用互斥量来保护共享数据,首先要定义和初始化互斥量。然后是使用互斥量的加锁、解锁来保护共享数据,最后使用完销毁互斥量。
✨3.1 互斥量的初始化
POSIX提供了两种初始化互斥量的方法。
-
1、是将
PTHREAD_MUTEX_INITIALIZER赋值给定义的互斥量,如下:#include <pthread.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;但这个方法没办法设置互斥量的属性,也不适用于动态分配的互斥量,比较少用。
-
2、使用
pthread_mutex_init初始化互斥量。如下:#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);第二个
pthread_mutexattr_t指针的入参,是用来设定互斥量的属性的。大部分情况下,并不需要设置互斥量的属性,传递NULL即可,表示使用互斥量的默认属性。
调用pthread_mutex_init之后, 互斥量处于没有加锁的状态。
✨3.2 互斥量的销毁
使用pthread_mutex_init初始化的互斥量,在确定不再需要互斥量的时候, 就要销毁它。 在销毁之前, 有三点需要注意:
1、使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量无须销毁。
2、不要销毁一个已加锁的互斥量, 或者是真正配合条件变量使用的互斥量。
3、已经销毁的互斥量, 要确保后面不会有线程再尝试加锁。
销毁互斥量的接口如下:
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
当互斥量处于已加锁的状态, 或者正在和条件变量配合使用, 调用pthread_mutex_destroy函数会返回EBUSY错误码。
✨3.3 互斥量的加锁和解锁
关于互斥量的加锁和解锁,POSIX提供了如下接口:
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock (pthread_mutex_t * mutex, const struct timespec *abstime);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
- pthread_mutex_lock:对互斥量加锁,如果互斥量未锁定,则将互斥量锁定, 同时返回成功。如果互斥量已经上锁,则一直阻塞等待互斥量解锁;
- pthread_mutex_trylock:对互斥量加锁,如果互斥量未锁定,则将互斥量锁定, 同时返回成功。如果互斥量已经上锁,则不会阻塞等待,直接返回
EBUSY; - pthread_mutex_timedlock:对互斥量加锁,如果互斥量未锁定,则将互斥量锁定, 同时返回成功。如果互斥量已经上锁,则等待
abstime设置的时间,如果还处于锁定状态,直接返回ETIMEOUT;注意,abstime是绝对时间,如果最多等待2分钟, 那么这个值应该是当前时间加上2分钟 - pthread_mutex_unlock:对互斥量解锁。
![]()
🎄四、互斥量的属性
线程和线程的同步对象(互斥量,读写锁,条件变量)都具有属性。在修改属性前都需要对该结构进行初始化。使用后要把该结构回收。大部分情况使用的都是默认属性。
互斥量的属性相关接口:
int pthread_mutexattr_init (pthread_mutexattr_t *attr); // 初始化互斥量属性为默认属性
int pthread_mutexattr_destroy (pthread_mutexattr_t *attr);// 销毁互斥量属性/* Get the process-shared flag of the mutex attribute ATTR. */
int pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr,int *pshared);/* Set the process-shared flag of the mutex attribute ATTR. */
int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int shared)
attr中pshared属性表示用这个属性对象创建的互斥锁的作用域,它的取值可以是PTHREAD_PROCESS_PRIVATE或PTHREAD_PROCESS_SHARED。
- PTHREAD_PROCESS_PRIVATE:默认属性,只有和创建这个互斥锁的线程在同一个进程中的线程才能访问这个互斥锁;
- PTHREAD_PROCESS_SHARED:所创建的互斥锁将被保存在共享内存中,可以被多个进程中的线程共享。
互斥锁类型:
- PTHREAD_MUTEX_NORMAL;
- PTHREAD_MUTEX_ERRORCHECK;
- PTHREAD_MUTEX_RECURSIVE;
- PTHREAD_MUTEX_DEFAULT。
![]()
🎄五、总结
本文介绍了Linux系统下,多线程编程常用的互斥量,先是介绍了需要互斥量的原因,然后介绍互斥量的使用,并给出使用例子。
下面是使用互斥量对第二小节例子进行修改后的代码:
// 08_mutex_test.c
// gcc 08_mutex_test.c -lpthread
#include <stdio.h>
#include <pthread.h>
#include <sys/syscall.h>
int g_Count = 0;
pthread_mutex_t g_mutex;
void *func(void *arg)
{int i=0;for(i=0; i<10000000; i++){pthread_mutex_lock(&g_mutex);g_Count++;pthread_mutex_unlock(&g_mutex);}return NULL;
}int main()
{pthread_mutex_init(&g_mutex, NULL);// 创建4个线程pthread_t threadId[4];int i=0;for(i=0; i<4; i++){pthread_create(&threadId[i], NULL, func, NULL);}for(i=0; i<4; i++){pthread_join(threadId[i],NULL);printf("join threadId=%lx\n",threadId[i]);}printf("g_Count=%d\n",g_Count);pthread_mutex_destroy(&g_mutex);return 0;
}

如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考:
《linux_多线程》
《Linux环境编程:从应用到内核》
相关文章:
【Linux C | 多线程编程】线程同步 | 互斥量(互斥锁)介绍和使用
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 ⏰发布时间⏰: 本文未经允许…...
mid_360建图和定位
录制数据 roslaunch livox_ros_driver2 msg_MID360.launch使用fast-lio 建图 https://github.com/hku-mars/FAST_LIO.git 建图效果 使用python做显示 https://gitee.com/linjiey11/mid360/blob/master/show_pcd.py 使用 point_lio建图 https://github.com/hku-mars/Point…...
ThreadX在STM32上的移植:通用启动文件tx_initialize_low_level.s
在嵌入式系统开发中,实时操作系统(RTOS)的选择对于系统性能和稳定性至关重要。ThreadX是一种广泛使用的RTOS,它以其小巧、快速和可靠而闻名。在本文中,我们将探讨如何将ThreadX移植到STM32微控制器上,特别是…...
【python实战】游戏开发——恐龙跳跃小游戏
目录 背景开发环境步骤初步搭建主窗口的实现地平线滑动场景小恐龙跳跃障碍物出现碰撞检测和积分功能优化改为随时可以跳跃源码参考背景 小恐龙沿着地平线前进,遇到障碍物跳跃,躲避障碍物。根据躲避的障碍物进行积分统计。 开发环境 开发环境:Windows10 软件:pycharm 开发…...
成都百洲文化传媒有限公司电商领域的新锐力量
在电商服务领域,成都百洲文化传媒有限公司凭借其专业的服务理念和创新的策略,正逐渐成为行业内的翘楚。这家公司不仅拥有资深的电商团队,还以其精准的市场定位和高效的服务模式,赢得了众多客户的信赖和好评。 一、专业团队&#…...
1042: 中缀表达式转换为后缀表达式
解法:直接给算法 创建一个栈和一个空的后缀表达式字符串。 遍历中缀表达式中的每个字符。 如果当前字符是操作数,直接将其添加到后缀表达式字符串中。 如果当前字符是操作符,需要将其与栈顶的操作符进行比较: 如果栈为空&#…...
避免上下文切换--Linux原子函数
在现代操作系统中,原子函数是一类特殊的函数,它们能够保证在并发环境中执行的操作是不可分割的。这意味着一旦一个原子函数开始执行,它的操作会在任何其他线程或进程可以介入之前完全完成。这是通过多种机制实现的,包括硬件支持的…...
塔面板php7.37.4版本不支持ZipArchive手工安装扩展方法
centos 7 宝塔面板安装的PHP7.3和7.4默认已经不带zip扩展,要手工安装zip扩展首先需要安装libzip, yum -y install libzip 方法如下: 宝塔面板php7.3版本在SSH命令行界面执行以下语句: cd /www/server/php/73/src/ext/zip/ /ww…...
go语言并发实战——日志收集系统(一) 项目前言
-goroutine- 简介 go并发编程的练手项目 项目背景 一般来说业务系统都有自己的日志,当系统出现问题时,我们一般需要通过日志信息来定位与解决问题,当系统机器较少时我们可以登录服务器来查看,但是当系统机器较多时,我们通过服务器来查看日志的成本就会变得很大,…...
Android Studio 之 Intent及其参数传递
一、Intent 显式Intent:通过组件名指定启动的目标组件,比如startActivity(new Intent(A.this,B.class)); 每次启动的组件只有一个~隐式Intent:不指定组件名,而指定Intent的Action,Data,或Category,当我们启动组件时, 会去匹配AndroidManifest.xml相关组件的Intent-…...
【黑马头条】-day06自媒体文章上下架-Kafka
文章目录 今日内容1 Kafka1.1 消息中间件对比1.2 kafka介绍1.3 kafka安装及配置1.4 kafka案例1.4.1 导入kafka客户端1.4.2 编写生产者消费者1.4.3 启动测试1.4.4 多消费者启动 1.5 kafka分区机制1.5.1 topic剖析 1.6 kafka高可用设计1.7 kafka生产者详解1.7.1 同步发送1.7.2 异…...
非线性特征曲线线性化插补器(CODESYS 完整ST代码)
1、如何利用博途PLC和信捷PLC实现非线性特征曲线的线性化可以参考下面文章链接: 非线性特征曲线线性化(插补功能块SCL源代码+C代码)_scl直线插补程序-CSDN博客文章浏览阅读382次。信捷PLC压力闭环控制应用(C语言完整PD、PID源代码)_RXXW_Dor的博客-CSDN博客闭环控制的系列文章…...
vue3从精通到入门4:diff算法的实现
Vue 3 的 diff 算法相较于 Vue 2 有了一些改进和优化,主要是为了应对更复杂的组件结构和更高的性能需求。 以下是 Vue 3 diff 算法在处理列表更新时的大致步骤: 头头比较:首先,比较新旧列表的头节点(即第一个节点&…...
(三)C++自制植物大战僵尸游戏项目结构说明
植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、项目结构 打开项目后,在解决方案管理器中有五个项目,分别是libbox2d、libcocos2d、librecast、libSpine、PlantsVsZombies五个项目,除PlantsVsZombies外,其他四个…...
动态规划专练( 279.完全平方数)
279.完全平方数 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 …...
京东商品详情API接口(商品属性丨sku价格丨详情图丨标题等数据)
京东商品详情API接口是京东开放平台提供的一种API接口,通过调用该接口,开发者可以获取京东商品的标题、价格、库存、月销量、总销量、详情描述、图片等详细信息。下面针对您提到的商品属性、SKU价格、详情图以及标题等数据,做具体介绍&#x…...
Springboot+Vue项目-基于Java+MySQL的校园周边美食探索及分享平台系统(附源码+演示视频+LW)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…...
折叠面板组件(vue)
代码 <template><div class"collapse-info"><div class"collapse-title"><div class"title-left">{{ title }}</div><div click"changeHide"> <Button size"small" v-if"sho…...
【Canvas技法】蓝底金字北岛诗节选(径向渐变色、文字阴影示例)
【效果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>北岛诗选</title><style type"text/css">.c…...
【大语言模型】基础:TF-IDF
TF-IDF (Term Frequency-Inverse Document Frequency) 是一种用于信息检索与文本挖掘的统计方法,用来评估一个词对于一个文件集或一个语料库中的其中一份文件的重要性。它是一种常用于文本处理和自然语言处理的权重计算技术。 原理 TF-IDF 由两部分组成࿱…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
