当前位置: 首页 > news >正文

如果持有互斥锁的线程没有解锁退出了,该如何处理?

文章目录

  • 如果持有互斥锁的线程没有解锁退出了,该如何处理?
    • 问题引入
    • 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对互斥锁的状态进行恢复。

相关文章:

如果持有互斥锁的线程没有解锁退出了,该如何处理?

文章目录如果持有互斥锁的线程没有解锁退出了&#xff0c;该如何处理&#xff1f;问题引入PTHREAD_MUTEX_ROBUST 和 pthread_mutex_consistent登场了结论&#xff1a;如果持有互斥锁的线程没有解锁退出了&#xff0c;该如何处理&#xff1f; 问题引入 看下面一段代码&#xf…...

信息论绪论

本专栏针包含信息论与编码的核心知识&#xff0c;按知识点组织&#xff0c;可作为教学或学习的参考。markdown版本已归档至【Github仓库&#xff1a;information-theory】&#xff0c;需要的朋友们自取。或者关注公众号【AIShareLab】&#xff0c;回复 信息论 也可获取。 文章目…...

Buffer Status Reporting(BSR)

欢迎关注同名微信公众号“modem协议笔记”。 以一个实网中的异常场景开始&#xff0c;大概流程是有UL data要发送&#xff0c;UE触发BSR->no UL grant->SR->no UL grant->trigger RACH->RACH fail->RLF->RRC reestablishment&#xff1a;简单描述就是UE触…...

代码随想录LeetCode | 单调栈问题

前沿&#xff1a;撰写博客的目的是为了再刷时回顾和进一步完善&#xff0c;其次才是以教为学&#xff0c;所以如果有些博客写的较简陋&#xff0c;是为了保持进度不得已而为之&#xff0c;还请大家多多见谅。 预&#xff1a;看到题目后的思路和实现的代码。 见&#xff1a;参考…...

C++之可调用对象、bind绑定器和function包装器

可调用对象在C中&#xff0c;可以像函数一样调用的有&#xff1a;普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象&#xff0c;统称可调用对象或函数对象。可调用对象有类型&#xff0c;可以用指针存储它们的地址&#xff0c;可…...

MongoDB--》文档查询的详细具体操作

目录 统计查询 分页列表查询 排序查询 正则的复杂条件查询 比较查询 包含查询 条件连接查询 统计查询 统计查询使用count()方法&#xff0c;其语法格式如下&#xff1a; db.collection.count(query,options) ParameterTypeDescriptionquerydocument查询选择条件optio…...

网络协议(六):网络层

网络协议系列文章 网络协议(一)&#xff1a;基本概念、计算机之间的连接方式 网络协议(二)&#xff1a;MAC地址、IP地址、子网掩码、子网和超网 网络协议(三)&#xff1a;路由器原理及数据包传输过程 网络协议(四)&#xff1a;网络分类、ISP、上网方式、公网私网、NAT 网络…...

热启动预示生态起航的Smart Finance,与深度赋能的SMART通证

2023年初加密市场的回暖&#xff0c;意味着各个赛道都将在新的一年里走向新的叙事。最近&#xff0c;我们看到GameFi赛道也在市场回暖的背景下&#xff0c;逐渐走出阴霾。从融资数据上看&#xff0c;1月获得融资的GameFi项目共12个&#xff0c;融资突破8000万美元&#xff0c;1…...

提分必练,中创教育PMP全真模拟题分享

湖南中创教育每日五题分享来啦&#xff0c;“日日行&#xff0c;不怕千万里&#xff1b;常常做&#xff0c;不怕千万事。”&#xff0c;每日五题我们练起来&#xff01; 1、在系统测试期间&#xff0c;按已识别原因的类型或类别记录了失败测试的数量。项目经理首先需要从最大故…...

PID控制算法基础介绍

PID控制的概念 生活中的一些小电器&#xff0c;比如恒温热水器、平衡车&#xff0c;无人机的飞行姿态和飞行速度控制&#xff0c;自动驾驶等等&#xff0c;都有应用到 PID——PID 控制在自动控制原理中是一套比较经典的算法。 为什么需要 PID 控制器呢&#xff1f; 你一定用…...

Ajax 学习笔记

一、Ajax1.1 什么是AjaxAJAX Asynchronous JavaScript and XML(异步的JavaScript和XML)。Ajax是一种在无需加载整个网页的情况下&#xff0c;能够更新部分网页的技术&#xff0c;它不是一种新的编程语言&#xff0c;而是一种用于创建更好更快以及交互性更强的Web应用程序的技术…...

​力扣解法汇总1234. 替换子串得到平衡字符串​

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 有一个只含有 Q, W, E, R 四种字符&#xff0c;且长度为 n 的字符串。 假如在该…...

C++关键字之const、inline、static

C 关键字总结 1.const const是 constant 的缩写&#xff0c;本意是不变的、不易改变的意思。在C中用来修饰内置类型变量&#xff0c;自定义对象&#xff0c;成员函数&#xff0c;返回值&#xff0c;函数参数使用如下&#xff1a; //修饰普通类型变量 const int a 7; int ba;…...

【成为架构师课程系列】怎样进行概念架构(Conceptual Architecture)?

目录 前言 什么是概念架构 概念架构阶段的3个步骤 初步设计 高层分割 分层式概念服务架构 Layer:逻辑层 Tier: 物理层 按通用性分层 技术堆叠 考虑非功能需求 【禅与计算机程序设计艺术&#xff1a;更多阅读】 前言 胜兵先胜而后求战&#xff0c;败兵先站而后求胜。…...

PostgreSQL的下载安装教程(macOS、Windows)

postgresql是GIS服务端几乎不可避免要打交道的数据库。因为mysql的空间扩展真是不尽人意。所以想要学会GIS服务端知识,postgresql(下文简称pg)你是必须要会的。 首先要知道,pg是一个空间数据库,和普通数据库不同的是pg支持空间数据的存储与操作。这里所谓的空间数据一般指…...

98年的确实卷,公司新来的卷王,我们这帮老油条真干不过.....

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;前段时间我们公司来了个00后&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 …...

软件架构知识2-系统复杂度

架构设计的真正目的&#xff1a;是为了解决软件系统复杂度带来的问题&#xff0c;一个解决方案。 系统复杂度&#xff0c;如何入手&#xff1a; 1、通过熟悉和理解需求&#xff0c;识别系统复杂性所在的地方&#xff0c;然后针对这些复杂点进行架构设计。 2、架构设计并不是要…...

JavaSE学习day4_02 数组(超级重点)

3.数组 3.1什么是数组 数组就是存储数据长度固定的容器&#xff0c;存储多个数据的数据类型要一致。 3.2数组定义格式 3.2.1第一种&#xff08;常用&#xff09; 数据类型[] 数组名 示例&#xff1a; int[] arr; double[] arr; char[] arr; 3.2.2第二种(在…...

Theano教程:Python的内存管理

在写大型程序时候的一大挑战是如何保证最少的内存使用率。但是在Python中的内存管理是比较简单的。Python显示分配内存&#xff0c;使用引用计数系统管理对象&#xff0c;当指向某一个对象的引用数变为 0 的时候&#xff0c;该对象所占的内存就会被释放。理论上听起来很不错&am…...

Linux | Liunx安装Tomcat(Ubuntu版)

目录 一、下载并上传Tomcat压缩包到Ubuntu 1.1 下载并解压 1.2 执行 startup.sh 文件 二、验证Tomcat启动是否成功 2.1 查看启动日志 2.2 查看启动进程 三、Windows访问 Tomcat 服务 四、停止 Tomcat 服务 Tomcat是一款Web服务器&#xff0c;开发Web项目基本上都会用到…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

xmind转换为markdown

文章目录 解锁思维导图新姿势&#xff1a;将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件&#xff08;ZIP处理&#xff09;2.解析JSON数据结构3&#xff1a;递归转换树形结构4&#xff1a;Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践

前言&#xff1a;本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中&#xff0c;跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南&#xff0c;你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案&#xff0c;并结合内网…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

验证redis数据结构

一、功能验证 1.验证redis的数据结构&#xff08;如字符串、列表、哈希、集合、有序集合等&#xff09;是否按照预期工作。 2、常见的数据结构验证方法&#xff1a; ①字符串&#xff08;string&#xff09; 测试基本操作 set、get、incr、decr 验证字符串的长度和内容是否正…...