Linux基础知识点(八-POSXI互斥锁)

目录

一、互斥锁基本概念

1.1 互斥相关背景概念

1.2 互斥锁(mutex) 

1.3 死锁 

二、初始化互斥锁

2.1 静态初始化 

 2.2 动态初始化

三、获取与释放互斥锁

四、销毁互斥锁 


 

一、互斥锁基本概念

1.1 互斥相关背景概念

  • 临界资源:多线程执行流共享的资源就叫做临界资源
  • 临界区:每个线程内部,访问临界资源的代码,就叫做临界区
  • 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。
  • 原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。

1.2 互斥锁(mutex) 

当不同进程/线程去访问某个临界资源的时候,就需要进行互斥保护, 这种互斥保护可以看做是一种锁机制,就好比当你去上厕所的时候,你会锁住门,不让别人进来。 在Linux系统中的锁机制是一个比较广泛的概念,而且锁的种类很多,包括互斥锁,文件锁,读写锁等等。

在初始化的时候,互斥锁处于开锁的状态,当互斥锁被线程持有时,该互斥锁处于闭锁状态,线程获得互斥锁的所有权。当该线程释放互斥锁时, 该互斥锁处于开锁状态,线程失去该互斥锁的所有权。也就是说,同时只有一个线程能获取互斥锁,特别地,持有该互斥锁的线程能够再次获得这个锁而不被阻塞, 这就是互斥锁的递归访问。互斥锁多用于保护临界资源。

 

1.3 死锁 

死锁就是自己把自己阻塞了,就相当于自己把自己锁在门外,钥匙在屋里。还有一种死锁的的情况是, 两个线程相互阻塞,就好比你家的钥匙在你朋友家,你朋友家的钥匙在你家,然后你们都进不去。想要避免死锁,最好遵循以下的规则:

  • 对共享资源操作前一定要获得锁。

  • 完成操作以后一定要释放锁。

  • 尽量短时间地占用锁。

  • 如果有多个锁,如获得顺序是ABC连环扣,释放顺序也应该是ABC。

二、初始化互斥锁

2.1 静态初始化 

在使用互斥锁前需要初始化一个互斥锁,而在POSIX标准中支持互斥锁静态初始化和动态初始化两种方式, 如果是静态初始化的可以通过以下代码实现(选择其中一句即可):

pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;

pthread_mutex_t是互斥锁的结构体,其实就是定义一个互斥锁结构,并且将其赋值,代表不同的互斥锁, 这3种锁的区别主要在于其他未占有互斥锁的线程在获取互斥锁时是否需要阻塞等待:

  • PTHREAD_MUTEX_INITIALIZER:表示默认的互斥锁,即快速互斥锁。互斥锁被线程1持有时,此时互斥锁处于闭锁状态, 当线程2尝试获取互斥锁,那么线程2将会阻塞直至持有互斥锁的线程1解锁为止。

  • PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP:递归互斥锁。互斥锁被线程1持有时,线程2尝试获取互斥锁, 将无法获取成功,并且阻塞等待,而如果是线程1尝试再次获取互斥锁时,将获取成功,并且持有互斥锁的次数加1。

  • PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP:检错互斥锁。这是快速互斥锁的非阻塞版本,它会立即返回一个错误代码(线程不会阻塞)。

 2.2 动态初始化

互斥锁动态初始化可以调用pthread_mutex_init()函数,该函数原型如下:

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

pthread_mutex_init()函数是以动态方式初始化互斥锁的,参数说明如下:

  • mutex则是初始化互斥锁结构的指针。

  • mutexattr是属性参数,它允许我们设置互斥锁的属性,从而属性控制着互斥锁的行为,如果参数mutexattr为NULL, 则使用默认的互斥锁属性,默认属性为快速互斥锁。

三、获取与释放互斥锁

线程对互斥锁的所有权是独占的,任意时刻互斥锁只能被一个线程持有,如果互斥锁处于开锁状态, 那么获取该互斥锁的线程将成功获得该互斥锁,并拥有互斥锁的所有权; 而如果互斥锁处于闭锁状态,则根据互斥锁的类型做对应的处理,默认情况下是快速互斥锁, 获取该互斥锁的线程将无法获得互斥锁,线程将被阻塞,直到互斥锁被释放,当然,如果是同一个线程重复获取互斥锁,也会导致死锁结果。获取互斥锁有2个函数,mutex参数指定了要操作的互斥锁:

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • pthread_mutex_lock()函数获得访问临界资源的权限,如果已经有其他线程锁住互斥锁,那么该函数会是线程阻塞指定该互斥锁解锁为止。

  • pthread_mutex_trylock()是pthread_mutex_lock()函数的非阻塞版本,使用它不会阻塞当前线程,如果互斥锁已被占用,它会理解返回一个EBUSY错误。

  • 访问完共享资源后,一定要通过pthread_mutex_unlock()函数释放占用的互斥锁,以便系统其他线程有机会获取互斥锁,访问该资源。

简单说就是,互斥锁的使用流程应该是

  1. 线程获取互斥锁。

  2. 然后访问共享资源。

  3. 最后释放互斥锁。

四、销毁互斥锁 

pthread_mutex_destroy()函数用于销毁一个互斥锁,当互斥锁不再使用时,可以用它来销毁,mutex参数指定了要销毁的互斥锁:

int pthread_mutex_destroy(pthread_mutex_t *mutex);
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>#define THREAD_NUMBER 3 /* 线程数 */pthread_mutex_t mutex;void *thread_func(void *arg)
{int num = (int)arg;int res;/* 互斥锁上锁 */res = pthread_mutex_lock(&mutex);if (res){   /*获取失败*/printf("Thread %d lock failed\n", num);/* 互斥锁解锁 */pthread_mutex_unlock(&mutex);pthread_exit(NULL);}printf("Thread %d is hold mutex\n", num);/*睡眠一定时间*/sleep(2);printf("Thread %d freed mutex\n\n", num);/* 互斥锁解锁 */pthread_mutex_unlock(&mutex);pthread_exit(NULL);
}int main(void)
{pthread_t thread[THREAD_NUMBER];int num = 0, res;/* 互斥锁初始化 */pthread_mutex_init(&mutex, NULL);for (num = 0; num < THREAD_NUMBER; num++){/*创建线程*/res = pthread_create(&thread[num], NULL, thread_func, (void*)num);if (res != 0){printf("Create thread %d failed\n", num);exit(res);}}for (num = 0; num < THREAD_NUMBER; num++){/*等待线程结束*/pthread_join(thread[num], NULL);}/*销毁互斥锁*/pthread_mutex_destroy(&mutex);return 0;
}

系统创建3个线程,假设这3个线程中有临界资源被访问,那么我们希望这3个线程按顺序且不能同时去访问这个临界资源(假设临界资源是调用sleep()函数),所以我们可以使用互斥锁去限制能访问的线程,获取到互斥锁的线程可以访问临界资源。从实验结果可以看到,线程访问临界资源的顺序每次执行顺序都是不一样的,并且临界区相同时间只允许一个线程访问。

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

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

相关文章

06.函数和模块的使用

函数和模块的使用 在讲解本章节的内容之前&#xff0c;我们先来研究一道数学题&#xff0c;请说出下面的方程有多少组正整数解。 事实上&#xff0c;上面的问题等同于将8个苹果分成四组每组至少一个苹果有多少种方案。想到这一点问题的答案就呼之欲出了。 可以用Python的程序来…

基于ssm的大湾区旅游推荐系统的设计与实现+vue论文

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统大湾区旅游景点信息管理难度大&#xff0c;容错率低&…

美创科技葛宏彬:夯实安全基础,对医疗数据风险“逐个击破”

导读 解决医疗机构“临床业务数据合规流动”与“重要数据安全防护”两大难题。 2023年11月11日&#xff0c;在2023年南湖HIT论坛上&#xff0c;HIT专家网联合杭州美创科技股份有限公司&#xff08;以下简称美创科技&#xff09;发布《医疗数据安全风险分析及防范实践》白皮书…

目标检测COCO数据集与评价体系mAP

1.mAP 2.IoU IoU也就是交并比&#xff0c;也称为 Jaccard 指数&#xff0c;用于计算真实边界框与预测边界框之间的重叠程度。它是真值框与预测边界框的交集和并集之间的比值。Ground Truth边界框是测试集中手工标记的边界框&#xff0c;用于指定目标图像的位置以及预测的边界框…

浅讲人工智能,初识人工智能几个重要领域。

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

Javaweb之Mybatis的XML配置文件的详细解析

2. Mybatis的XML配置文件 Mybatis的开发有两种方式&#xff1a; 注解 XML 2.1 XML配置文件规范 使用Mybatis的注解方式&#xff0c;主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能&#xff0c;建议使用XML来配置映射语句&#xff0c;也就是将SQL语句写在…

顺序表的实现(C语言)

本文章主要对顺序表的介绍以及数据结构的定义,以及几道相关例题,帮助大家更好理解顺序表. 文章目录 前言 一、顺序表的静态实现 二、顺序表的动态实现 三.定义打印顺序表函数 四.定义动态增加顺序表长度函数 五.创建顺序表并初始化 六.顺序表的按位查找 七.顺序表的按值…

如何下载 GOES(Geostationary Operational Environmental Satellite)卫星数据

GOES是指地球静止轨道卫星&#xff08;Geostationary Operational Environmental Satellite&#xff09;系统&#xff0c;它是美国国家海洋和大气管理局&#xff08;NOAA&#xff09;和美国国家航空航天局&#xff08;NASA&#xff09;合作开发和运营的一系列气象卫星。这些卫星…

如何编写高效的正则表达式?

正则表达式&#xff08;Regular Expression&#xff0c;简称regex&#xff09;是一种强大的文本处理技术&#xff0c;广泛应用于各种编程语言和工具中。本文将从多个方面介绍正则表达式的原理、应用和实践&#xff0c;帮助你掌握这一关键技术。 正则可视化 | 一个覆盖广泛主题…

19、Kubernetes核心技术 - 资源限制

目录 一、概述 二、Kubernetes 中的资源单位 2.1、CPU资源单位 2.2、内存资源单位 三、Pod资源限制 四、namespace资源限制 4.1、为命名空间配置内存和 CPU 配额 4.2、为命名空间配置默认的内存请求和限制 4.3、为命名空间配置默认的CPU请求和限制 五、超过容器限制的…

240107-RHEL8+RHEL9配置安装:NVIDIA驱动(15步)+CUDA(4步)+CUDNN(5步)+GPU压力测试

Section 0: 基础知识 CUDA、cuDNN 和 PyTorch 版本的选择与搭配指南 安装优先级: 显卡驱动 → CUDA → CUDA Toolkit → cuDNN → Pytorch 即显卡驱动决定了CUDA版本&#xff0c;CUDA版本决定了CUDA Toolkit、cuDNN、Pytorch各自的版本提前下载 &#xff5c; CUDA提前下载 &am…

超自动化助力企业财务转型升级

在快节奏的财务规划与分析环境中&#xff0c;传统的预算方法虽长期以来一直是企业制定有效决策的支柱&#xff0c;但已不足以驾驭当今复杂的商业环境。不断的经济变化、市场的不确定性以及利益相关者的需求增加促使企业寻求更敏捷的解决方案。如今&#xff0c;部分企业开始尝试…

lc 140. 单词拆分 II

回溯算法查询匹配单词 class Solution { public:unordered_map<string, int> word_map;void mapping(vector<string>& wordDict){for(auto &a : wordDict)word_map[a];}vector<string> ret;// s: 原始字符串// tmp: 已查询到的单词// …

CSS 彩虹按钮效果

<template><view class"content"><button class"btn">彩虹按钮</button></view> </template><script></script><style>body{background-color: #000;}.content {margin-top: 300px;}.btn {width: 1…

Debian12使用Xshell连接失败解决办法详细

1、Debian开启ssh服务 sudo apt update -y sudo apt install ssh2、编辑配置文件 # 安装vim sudo apt install vimvim /etc/ssh/sshd_config3、将#PermitRootLogin prohibit-password的注释去掉&#xff0c;设置为yes 4、将#PasswordAuthentication no的注释去掉&#xff0c;…

JAVA------IO流复制总结

IO流复制文件 方法一 字符 注意点&#xff1a;写和读需要保持一致的编码形式。 public class eee {public static void main(String[] args) {FileInputStream in null;FileOutputStream out null;OutputStreamWriter outw null;InputStreamReader inr null;try{out new …

VX小程序Burp抓包

方法有很多&#xff0c;工具也各有差异&#xff0c;主要是学代理流量的思路 Burp流量代理工具小程序 一、Burp证书导入 1、开启代理 开启浏览器的代理&#xff0c;火狐推荐FoxyProxy&#xff0c;Google推荐SwitchyOmega&#xff0c;设置代理为127.0.0.1:8080。 2、下载证书…

Apache Doris (六十三): Spark Doris Connector - (3)-配置型及列映射关系

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你学编程的个人空间-豹哥教你学编程个人主页-哔哩哔哩视频 目录 1. Spark 操作Doris配置项…

2023量子科技十大人物(团队) | 光子盒年度系列

今年&#xff0c;是量子科学与技术的又一个丰收年&#xff0c;学术研究团体和科技公司纷纷庆祝在量子计算、量子通信和量子计量学以及基础量子科学方面取得的重大成就。面对如此多令人兴奋的进展&#xff0c;我们不能不为这些进展庆祝——而所有这些的一切&#xff0c;都离不开…

深入了解static关键字的作用和应用--java面向对象学习

Static修饰成员变量 Static是什么 叫静态&#xff0c;可以修饰成员变量&#xff0c;成员方法 成员变量按有无static修饰分俩种&#xff1a; 类变量&#xff1a;有static修饰&#xff0c;属于类&#xff0c;在计算机里只有一份&#xff0c;会被类的全部对…