如果持有互斥锁的线程没有解锁退出了,该如何处理?
文章目录
- 如果持有互斥锁的线程没有解锁退出了,该如何处理?
- 问题引入
- PTHREAD_MUTEX_ROBUST 和 pthread_mutex_consistent登场了
- 结论:
如果持有互斥锁的线程没有解锁退出了,该如何处理?
问题引入
看下面一段代码,两个线程将竞争互斥锁mutex而进入临界区, 线程2在竞争互斥锁之前会sleep 2秒, 因此大概率线程1将获得互斥锁。 然而线程1执行完临界区的代码之后, 没有执行解锁操作,就退出了。
这样会导致线程2将死锁,因为该锁的状态将永远是锁定状态, 它将永远都不能获得锁。
#include<unistd.h>
#include<sys/mman.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include <string>
#include <iostream>
using namespace std;
pthread_mutex_t mutex;void* func1(void* param)
{pthread_mutex_lock(&mutex);cout << "func1 get lock" << endl;pthread_exit(NULL);
}void* func2(void* param)
{sleep(2);pthread_mutex_lock(&mutex);cout << "func2 get lock" << endl;pthread_mutex_unlock(&mutex);return NULL;
}int main(void)
{int i;pthread_mutex_init(&mutex, NULL);pthread_t tid1, tid2;pthread_create(&tid1, NULL, func1, NULL);pthread_create(&tid2, NULL, func2, NULL);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_mutex_destroy(&mutex);return 0;
}
那么遇到这种情况该如何处理呢?
PTHREAD_MUTEX_ROBUST 和 pthread_mutex_consistent登场了
首先给出解决方案,如果出现了上述的场景,就需要使用互斥锁的PTHREAD_MUTEX_ROBUST属性和pthread_mutex_consistent函数。
设置PTHREAD_MUTEX_ROBUST属性需要使用pthread_mutexattr_setrobust函数, 其原型如下:
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr,int robust);
使用了该属性之后,如果某个持有互斥锁的线程还没有释放互斥锁就退出的话, 那么其他线程在进行加锁时将会收到一个EOWNERDEAD的错误,这就提示加锁线程, 目前持有锁的线程已经死亡, 可以对互斥锁的状态进行重置。
而重置的过程就需要使用到pthread_mutex_consistent方法。
#include <pthread.h>int pthread_mutex_consistent(pthread_mutex_t *mutex);
#include<unistd.h>
#include<sys/mman.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include <string>
#include <iostream>
using namespace std;
pthread_mutex_t mutex;void* func1(void* param)
{pthread_mutex_lock(&mutex);cout << "func1 get lock" << endl;pthread_exit(NULL);
}void* func2(void* param)
{sleep(2);int r = pthread_mutex_lock(&mutex);if (r == EOWNERDEAD){cout << "thread2 will unlock the lock" << endl;pthread_mutex_consistent(&mutex);} cout << "func2 get lock" << endl;pthread_mutex_unlock(&mutex);return NULL;
}int main(void)
{int i;pthread_mutexattr_t attr;int err = pthread_mutexattr_init(&attr);if (err != 0)return err;pthread_mutexattr_setrobust(&attr,PTHREAD_MUTEX_ROBUST); pthread_mutex_init(&mutex, &attr);pthread_t tid1, tid2;pthread_create(&tid1, NULL, func1, NULL);pthread_create(&tid2, NULL, func2, NULL);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_mutex_destroy(&mutex);return 0;
}
需要特别注意的是,如果owner死亡后,这个锁的继任者,没有调用pthread_mutex_consistent恢复锁的一致性的话,那么后续对该锁的操作除了pthread_mutex_destroy以外, 其他的操作都将失败, 并且返回ENOTRECOVERABLE错误,意味着该锁彻底可再用了, 只有将其销毁。
#include<unistd.h>
#include<sys/mman.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include <string>
#include <iostream>
using namespace std;
pthread_mutex_t mutex;void* func1(void* param)
{pthread_mutex_lock(&mutex);cout << "func1 get lock" << endl;pthread_exit(NULL);
}void* func2(void* param)
{sleep(2);int r = pthread_mutex_lock(&mutex);
/* if (r == EOWNERDEAD){cout << "thread2 will unlock the lock" << endl;pthread_mutex_consistent(&mutex);}
*/cout << "func2 get lock" << endl;pthread_mutex_unlock(&mutex);return NULL;
}void* func3(void* param)
{sleep(10);int r = pthread_mutex_lock(&mutex);cout << "err = " << r << endl;
/* if (r == EOWNERDEAD){cout << "thread2 will unlock the lock" << endl;pthread_mutex_consistent(&mutex);}
*/cout << "func3 get lock" << endl;pthread_mutex_unlock(&mutex);return NULL;
}int main(void)
{int i;pthread_mutexattr_t attr;int err = pthread_mutexattr_init(&attr);if (err != 0)return err;pthread_mutexattr_setrobust(&attr,PTHREAD_MUTEX_ROBUST);pthread_mutex_init(&mutex, &attr);pthread_t tid1, tid2, tid3;pthread_create(&tid1, NULL, func1, NULL);pthread_create(&tid2, NULL, func2, NULL);pthread_create(&tid3, NULL, func3, NULL);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);pthread_mutex_destroy(&mutex);return 0;
}
结论:
- 在多线程/多进程程序中,离开临界区时候一定需要释放互斥锁。 可以使用RAII的设计方法, 离开作用域的时候栈对象析构, 从而释放锁。
- 在多线程/多进程程序中,如果持有锁的owner意外退出,如果还想继续使用该锁, 那么该锁的后续的owner需要使用PTHREAD_MUTEX_ROBUST和pthread_mutex_consistent对互斥锁的状态进行恢复。
相关文章:
如果持有互斥锁的线程没有解锁退出了,该如何处理?
文章目录如果持有互斥锁的线程没有解锁退出了,该如何处理?问题引入PTHREAD_MUTEX_ROBUST 和 pthread_mutex_consistent登场了结论:如果持有互斥锁的线程没有解锁退出了,该如何处理? 问题引入 看下面一段代码…...
信息论绪论
本专栏针包含信息论与编码的核心知识,按知识点组织,可作为教学或学习的参考。markdown版本已归档至【Github仓库:information-theory】,需要的朋友们自取。或者关注公众号【AIShareLab】,回复 信息论 也可获取。 文章目…...
Buffer Status Reporting(BSR)
欢迎关注同名微信公众号“modem协议笔记”。 以一个实网中的异常场景开始,大概流程是有UL data要发送,UE触发BSR->no UL grant->SR->no UL grant->trigger RACH->RACH fail->RLF->RRC reestablishment:简单描述就是UE触…...
代码随想录LeetCode | 单调栈问题
前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。 预:看到题目后的思路和实现的代码。 见:参考…...
C++之可调用对象、bind绑定器和function包装器
可调用对象在C中,可以像函数一样调用的有:普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。可调用对象有类型,可以用指针存储它们的地址,可…...
MongoDB--》文档查询的详细具体操作
目录 统计查询 分页列表查询 排序查询 正则的复杂条件查询 比较查询 包含查询 条件连接查询 统计查询 统计查询使用count()方法,其语法格式如下: db.collection.count(query,options) ParameterTypeDescriptionquerydocument查询选择条件optio…...
网络协议(六):网络层
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
热启动预示生态起航的Smart Finance,与深度赋能的SMART通证
2023年初加密市场的回暖,意味着各个赛道都将在新的一年里走向新的叙事。最近,我们看到GameFi赛道也在市场回暖的背景下,逐渐走出阴霾。从融资数据上看,1月获得融资的GameFi项目共12个,融资突破8000万美元,1…...
提分必练,中创教育PMP全真模拟题分享
湖南中创教育每日五题分享来啦,“日日行,不怕千万里;常常做,不怕千万事。”,每日五题我们练起来! 1、在系统测试期间,按已识别原因的类型或类别记录了失败测试的数量。项目经理首先需要从最大故…...
PID控制算法基础介绍
PID控制的概念 生活中的一些小电器,比如恒温热水器、平衡车,无人机的飞行姿态和飞行速度控制,自动驾驶等等,都有应用到 PID——PID 控制在自动控制原理中是一套比较经典的算法。 为什么需要 PID 控制器呢? 你一定用…...
Ajax 学习笔记
一、Ajax1.1 什么是AjaxAJAX Asynchronous JavaScript and XML(异步的JavaScript和XML)。Ajax是一种在无需加载整个网页的情况下,能够更新部分网页的技术,它不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术…...
力扣解法汇总1234. 替换子串得到平衡字符串
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 有一个只含有 Q, W, E, R 四种字符,且长度为 n 的字符串。 假如在该…...
C++关键字之const、inline、static
C 关键字总结 1.const const是 constant 的缩写,本意是不变的、不易改变的意思。在C中用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数使用如下: //修饰普通类型变量 const int a 7; int ba;…...
【成为架构师课程系列】怎样进行概念架构(Conceptual Architecture)?
目录 前言 什么是概念架构 概念架构阶段的3个步骤 初步设计 高层分割 分层式概念服务架构 Layer:逻辑层 Tier: 物理层 按通用性分层 技术堆叠 考虑非功能需求 【禅与计算机程序设计艺术:更多阅读】 前言 胜兵先胜而后求战,败兵先站而后求胜。…...
PostgreSQL的下载安装教程(macOS、Windows)
postgresql是GIS服务端几乎不可避免要打交道的数据库。因为mysql的空间扩展真是不尽人意。所以想要学会GIS服务端知识,postgresql(下文简称pg)你是必须要会的。 首先要知道,pg是一个空间数据库,和普通数据库不同的是pg支持空间数据的存储与操作。这里所谓的空间数据一般指…...
98年的确实卷,公司新来的卷王,我们这帮老油条真干不过.....
都说00后躺平了,但是有一说一,该卷的还是卷。这不,前段时间我们公司来了个00后,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 …...
软件架构知识2-系统复杂度
架构设计的真正目的:是为了解决软件系统复杂度带来的问题,一个解决方案。 系统复杂度,如何入手: 1、通过熟悉和理解需求,识别系统复杂性所在的地方,然后针对这些复杂点进行架构设计。 2、架构设计并不是要…...
JavaSE学习day4_02 数组(超级重点)
3.数组 3.1什么是数组 数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致。 3.2数组定义格式 3.2.1第一种(常用) 数据类型[] 数组名 示例: int[] arr; double[] arr; char[] arr; 3.2.2第二种(在…...
Theano教程:Python的内存管理
在写大型程序时候的一大挑战是如何保证最少的内存使用率。但是在Python中的内存管理是比较简单的。Python显示分配内存,使用引用计数系统管理对象,当指向某一个对象的引用数变为 0 的时候,该对象所占的内存就会被释放。理论上听起来很不错&am…...
Linux | Liunx安装Tomcat(Ubuntu版)
目录 一、下载并上传Tomcat压缩包到Ubuntu 1.1 下载并解压 1.2 执行 startup.sh 文件 二、验证Tomcat启动是否成功 2.1 查看启动日志 2.2 查看启动进程 三、Windows访问 Tomcat 服务 四、停止 Tomcat 服务 Tomcat是一款Web服务器,开发Web项目基本上都会用到…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
