如果持有互斥锁的线程没有解锁退出了,该如何处理?
文章目录
- 如果持有互斥锁的线程没有解锁退出了,该如何处理?
- 问题引入
- 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项目基本上都会用到…...
缓冲区浅析
缓冲区 程序运行输入数据时,从键盘的输入先存储到缓冲区,只有当缓冲区满或者输入回车时程序才会真正地从缓冲区读入数据 int main() {int a, b;cin >> a >> b;return 0; }in: 1 2\n 例如这里输入空格时程序没有输出,而是将空格…...
Day888.MySQL是怎么保证主备一致的 -MySQL实战
MySQL是怎么保证主备一致的 Hi,我是阿昌,今天学习记录的是关于MySQL是怎么保证主备一致的内容。 MySQL 能够成为现下最流行的开源数据库,binlog 功不可没。 在最开始,MySQL 是以容易学习和方便的高可用架构,被开发人…...
互联网舆情监测系统的发展阶段,TOOM互联网舆情监测系统有哪些?
互联网舆情监测系统是一种利用计算机技术对互联网上的大量信息进行实时监测、分析和评估的工具,旨在了解公众对某一事件、话题或品牌等的态度、情感倾向和影响力等。通过对社交媒体、论坛、新闻媒体等多个渠道的数据采集和处理,系统能够实现舆情事件的追…...
GIT命令操作大全
文章目录一、前言二、工作模块2.1 Workspace:工作区2.2 Index / Stage:暂存区2.3 Repository:本地仓库2.4Remote:远程仓库三、GIT基本配置四、GIT项目代码管理4.1 初始化git仓库4.2 提交到暂存区(stage)4.3 将暂存区的文件恢复到工…...
突破传统开发模式,亚马逊云科技助力中科院加速推动合成生物学
当数字技术成为整个社会运行的底座,生物科学也能借力云计算从诸多繁琐重复的工作中解放出来,专注于生物设计与创新。来看看亚马逊云科技如何与TIBCAS合作,推动合成生物学的发展。 明确核心需求,选择合作伙伴 TIBCAS选择与亚马逊…...
分享开放通达信l2接口的过程,开发之后怎么使用?
随着互联网的不断进步,信息技术的不断发展,通达信l2接口技术逐步成熟。那么,这些开放通达信l2接口开发的过程是怎么样的呢?期间又会遇到什么问题,开放之后又会怎么使用呢?这篇文章带你深入了解。 通达信l2接口不像一…...
33、基于51单片机老人防跌倒蜂鸣器报警系统加速度检测
背景技术 老年人出门由于身体不灵活、视力较差,容易发生跌倒,现用的老年人跌倒报警装置是通过无线对讲系统研发的,它外观精美,自动化程度高,有很强的专业性,但是,设计者忽略了一个问题…...
【项目】基于SpringBoot+Freemarker+Mybatis+MySQL+LayUI实现CRM智能办公系统
这里写目录标题CRM基本概念CRM分类模块功能描述项目代码application-dev.yml部分页面代码CRM基本概念 圈内存在这么一句话:“世上本来没有 CRM,大家的生意越来越难做了,才有了 CRM。” 在同质化竞争时代,顾客资产尤为重要&#x…...
手写识别字体的步骤是什么?怎么识别图片中的文字?
手写识别字体的步骤是什么?怎么识别图片中的文字? 1. 打开信风工具网,点击拍照按钮,选择拍图识字模式,对准需要识别的文件进行拍摄。在线工具地址: https://ocr.bytedance.zj.cn/image/ImageT…...
Mysql 存储过程
什么是存储过程? 存储过程是事先经过编译并存储在数据库的一段sql语句的集合 如何创建一个存储过程? create procedure 存储过程名称([参数列表]) beginsql语句; end#例 create procedure p1() beginselect * from t_goods;select * from t_user; end如…...
代做网站 猪八戒网/友情链接购买网站
1、获取数组最后一个位置的值 比较常规的是:$arr[count($arr)-1]; 貌似还有一个数组函数end();可以直接获取最后一个元素的值。相应的还有reset(),next(),current(),prev(); 本文转自 努力的C 51CTO博客,原文链接:http://blog.51cto.com/fulin0532/1966245...
口碑好的句容网站建设/免费做做网站
在Android项目中使用到了org.apache.commons.codec.jar包下的Hex.encodeHexString(byte[] input)方法进行加密。结果编译通过,运行时总是报java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString([B)Ljava/lang/String;错误。 原因&am…...
企业网查询官网在线登录入口/seo学习
使用过滤器: 在web-inf/classes/ 下添加filters/SetCharacterEncodingFilter.class 这个类可在tomcat_home/webapps/examples/web-inf/classes/filters/下找到。web.xml文件中加入: <filter> <filter-name>Set Character Enco…...
wordpress教程视频/广州短视频代运营
最近再次用到的一段代码,在此记录一下。 网上找了一圈,实在是找不到原文了。 算法大概是:先定位最左边并且最上面的点,计算这个点与其他点的夹角,找出顺时针转角最小的。按此规则依次递归,直到再次回到原点…...
山东日照网站建设/千锋教育培训怎么样
Microsoft PetShop 3.0 设计与实现--数据访问层 最近对多层设计实现和.Net产生了兴趣,从而研究了一下比较著名的多层范例程序――PetShop,现在的版本是3.0,和以前的版本从设计上已有一定的区别,应该是和Java的Petshop设计相当。 关…...
咋做黄页网站/精准推广
...