linux c 递归锁的介绍
递归锁的递归特性确实只是对于持有锁的线程。当一个线程获取了递归锁后,它可以多次重复获取该锁,而不会导致自身阻塞或死锁。这是递归锁的重要特点,它允许同一个线程在已经持有锁的情况下,再次获取相同的锁。
然而,对于其他线程,如果该递归锁已经被某个线程持有(即使是持有锁的线程自身多次获取的),那么其他线程在尝试获取该锁时,仍然会被阻塞,直到持有锁的线程进行了相应次数的解锁操作,使得锁完全释放后,其他线程才有机会获取该锁。
递归锁通常应用于递归函数或方法,以及存在嵌套临界区的情况。在这些场景下,同一个线程可能需要在不同的递归层次或嵌套的临界区中多次获取同一个锁。通过使用递归锁,可以确保线程不会因为自身重复获取锁而产生死锁问题。
需要注意的是,使用递归锁时,持有锁的线程必须进行相应次数的解锁操作,以平衡之前的加锁操作。也就是说,对于每次加锁,都需要有一个对应的解锁,只有当解锁次数与加锁次数相等时,锁才会完全释放,其他线程才能获取该锁。如果解锁次数不足或过多,都可能导致死锁或其他同步问题的发生。
如在一个递归函数中,每次递归调用都需要获取相同的锁进行保护,递归锁就可以满足这种需求。而如果使用普通的互斥锁,在同一线程中再次尝试获取已经持有的锁时,就会导致死锁。
PTHREAD_MUTEX_RECURSIVE 是一种递归锁,它允许同一个线程对同一个锁成功获得多次,并通过多次 unlock 解锁。
使用 PTHREAD_MUTEX_RECURSIVE 递归锁的一般步骤如下:
- 包含必要的头文件:
#include <pthread.h>
。 - 初始化互斥锁属性对象:使用
pthread_mutexattr_init(&attr);
初始化一个互斥锁属性对象attr
。 - 设置锁的类型为递归锁:通过
pthread_mutexattr_settype(&attr, pthread_mutex_recursive);
将互斥锁的类型设置为递归锁。 - 初始化递归锁:使用
pthread_mutex_init(&mutex, &attr);
初始化递归锁mutex
,并关联之前设置好属性的attr
对象。 - 在需要加锁的代码段前加锁:通过
pthread_mutex_lock(&mutex);
进行加锁操作。如果是在同一个线程中且之前已经加过锁,不会产生死锁,而是可以成功再次加锁。 - 在相应的代码段结束后解锁:调用
pthread_mutex_unlock(&mutex);
释放锁。需要注意的是,加锁几次就需要解锁几次,才能完全释放该锁,以便其他线程获取该锁。 - 不再使用递归锁后,销毁互斥锁:使用
pthread_mutex_destroy(&mutex);
释放锁资源。
下面是一个简单的示例代码,演示了递归锁的使用:
#include<pthread.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>pthread_mutex_t mutex;
pthread_mutexattr_t attr;void*func(void*arg){if(*(char*)arg=='\0') return NULL;pthread_mutex_lock(&mutex); // 加锁char*str = (char*)arg;while(*str!='\0'){fputc(*str, stdout);str++;}fputc('\n', stdout);func((char*)arg + 1); // 递归调用自身,再次加锁pthread_mutex_unlock(&mutex); // 解锁return NULL;
}int main()
{int ret;if((ret=pthread_mutexattr_init(&attr))!=0){ // 初始化互斥锁属性对象fprintf(stderr, "create mutex attribute error.msg:%s", strerror(ret));exit(1);}pthread_mutexattr_settype(&attr, pthread_mutex_recursive); // 设置为递归锁属性pthread_mutex_init(&mutex, &attr); // 初始化递归锁pthread_t p1, p2;char str1[8], str2[8];sprintf(str1, "abcdefg");sprintf(str2, "1234567");if((ret=pthread_create(&p1, NULL, func, str1))!=0){ // 创建线程 p1 并执行 func 函数fprintf(stderr, "create thread error.msg:%s", strerror(ret));exit(1);}if((ret=pthread_create(&p2, NULL, func, str2))!=0){ // 创建线程 p2 并执行 func 函数fprintf(stderr, "create thread error.msg:%s", strerror(ret));exit(1);}pthread_join(p1, NULL); // 等待线程 p1 结束pthread_join(p2, NULL); // 等待线程 p2 结束
}
在上述示例中,func
函数中存在递归调用,并且在递归调用时会再次对同一个锁进行加锁操作。如果使用普通的互斥锁(非递归锁),则会导致死锁。而使用 PTHREAD_MUTEX_RECURSIVE 递归锁,就可以在同一个线程中多次加锁而不会产生死锁。
需要注意的是,虽然递归锁提供了方便,但也应该谨慎使用,尽量避免在不必要的情况下过度使用递归锁,因为它可能会导致一些难以察觉的逻辑错误或性能问题。在实际编程中,确保正确地管理锁的获取和释放次数,以避免出现意外的情况。另外,在使用完递归锁后,记得使用 pthread_mutex_destroy
函数销毁锁,以释放相关资源。
在POSIX标准中,递归互斥锁的类型通常被定义为PTHREAD_MUTEX_RECURSIVE
。但是在一些GNU系统(如Linux),PTHREAD_MUTEX_RECURSIVE
常被定义为PTHREAD_MUTEX_RECURSIVE_NP
,其中NP
代表“Non-Portable”(非可移植的)。
具体来说:
PTHREAD_MUTEX_RECURSIVE
:POSIX标准定义的递归互斥锁类型。这在POSIX兼容的系统中应该可以直接使用。PTHREAD_MUTEX_RECURSIVE_NP
:GNU特定的递归互斥锁类型。在一些GNU系统中,这个宏定义被用来替代标准的PTHREAD_MUTEX_RECURSIVE
。
通常,POSIX兼容系统(如现代的Linux发行版)应该支持PTHREAD_MUTEX_RECURSIVE
。但是,如果你的系统使用了较旧的或特定的GNU库版本,你可能需要使用PTHREAD_MUTEX_RECURSIVE_NP
。
检查和使用合适的宏
为了编写兼容性更好的代码,可以在编译时检查是否定义了PTHREAD_MUTEX_RECURSIVE
,并根据需要使用适当的宏。例如:
#include <pthread.h>int main() {pthread_mutexattr_t attr;pthread_mutexattr_init(&attr);#ifdef PTHREAD_MUTEX_RECURSIVEpthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#elsepthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#endif// 其余代码...pthread_mutexattr_destroy(&attr);return 0;
}
定义_GNU_SOURCE
在包含<pthread.h>
之前定义_GNU_SOURCE
宏也可以启用所有GNU扩展功能,确保PTHREAD_MUTEX_RECURSIVE
宏被正确识别:
#define _GNU_SOURCE
#include <pthread.h>// 其余代码...
相关文章:
linux c 递归锁的介绍
递归锁的递归特性确实只是对于持有锁的线程。当一个线程获取了递归锁后,它可以多次重复获取该锁,而不会导致自身阻塞或死锁。这是递归锁的重要特点,它允许同一个线程在已经持有锁的情况下,再次获取相同的锁。 然而,对…...
React好用的组件库有哪些
React好用的组件库有很多,它们各自具有不同的特点和优势,适用于不同的开发场景和需求。以下是一些受欢迎的React组件库及其特点: Material-UI(现更名为MUI) 特点:这是一个开源的React组件库,实…...

简单快捷!Yarn的安装与使用指南
Yarn 是由 Facebook (现 Meta) 开发的包管理工具。 今天,我将介绍如何使用 Yarn。 目录 Yarn 的官方网站 关于安装 版本确认 开始一个新项目(创建 package.json 文件) 安装软件包 升级包 运行脚本 执行包的命令 卸载包 总结 Yarn 的…...

【Django】前端技术-网页样式表CSS
文章目录 一、申明规则CSS的导入方式行内样式内部样式外部样式 二、CSS的选择器1. 基本选择器标签选择器: 选择一类标签 标签{}类选择器 class: 选择所有class属性一致的表情,跨标签.类名{}ID选择器:全局唯一 #id名{} 2.层次选择器…...
openssl req 详解
一、openssl req 该命令用于创建和处理PKCS#10格式的证书请求(certificate requests CSRs),也可以用来创建自签名证书( self-signed certificates)来当作根证书(root CAs)使用 -new 该选项用来…...
mysql各种锁总结
mysql全局锁 读锁(共享锁) 阻止其他用户更新,但允许他们读取数据。 写锁(排他锁) 阻止其他用户读取和更新数据。 全局锁场景:进行数据库备份 数据库备份 背景:备份数据肯定要保证数据一致…...
SpringSecurity--DelegatingFilterProxy工作流程
什么是 DelegatingFilterProxy? DelegatingFilterProxy 是 Spring 提供的一个特殊的过滤器,它起到了桥梁的作用,可以让你在 Spring 容器中管理 Servlet 容器中的过滤器。 为什么需要 DelegatingFilterProxy? 通常情况下&#x…...
GitHub每日最火火火项目(7.27)
1. 项目名称:meta - llama / llama3 项目介绍:这是 Meta Llama 3 的官方 GitHub 站点。目前尚不清楚该项目的具体功能和特点,但从名称推测,可能与 Llama 3 模型相关,或许涉及到模型的开发、训练或应用等方面。 项目地…...

git 学习总结
文章目录 一、 git 基础操作1、工作区2、暂存区3、本地仓库4、远程仓库 二、git 的本质三、分支git 命令总结 作者: baron 一、 git 基础操作 如图所示 git 总共有几个区域 工作区, 暂存区, 本地仓库, 远程仓库. 1、工作区 存放项目代码的地方,他有两种状态 Unm…...

《如何找到自己想做的事》
Arouse Enthusiasm, Give Scope to Skill, Explore The Essence *摘其两纸 我喜欢打篮球,并不是我真的喜欢这项运动,而是我喜欢团队竞技。我喜欢看书,并不是我真喜欢阅读,而是我想要了解世界运行逻辑。寻找热爱,探寻本…...

Vue中el的两种写法
大家好我是前端寄术区博主PleaSure乐事。今天了解到了Vue当中有关el的两种写法,记录下来与大家分享,希望对大家有所帮助。 方法一 解释 第一种方法我们直接用new创建并初始化一个新的 Vue 实例,并定义了 Vue 实例的数据对象,在给…...

ELK安装(Elasticsearch+Logstash+Kibana+Filebeat)
一、简介 1.1、软件简介 ELK其实是Elasticsearch,Logstash 和 Kibana三个产品的首字母缩写,这三款都是开源产品。 1.1.1、Elasticsearch简介 Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析…...

VScode使用Github Copilot插件时出现read ECONNREST问题的解决方法
文章目录 read ECONNREST查看是否仍是 Copilot 会员查看控制台输出网络连接问题浏览器设置问题笔者的话 read ECONNREST 最近使用 Copilot 时一直出现 read ECONNREST 问题,这个表示连接被对方重置了,就是说在读取数据时连接被关闭。 我首先怀疑是不是…...

充电桩浪涌保护方案—保障充电设施安全稳定运行的关键
在当今新能源汽车蓬勃发展的时代,充电桩作为电动汽车的“加油站”,其重要性不言而喻。然而,由于其复杂的电气环境和暴露于户外的特点,充电桩容易受到浪涌的影响。浪涌可能来自雷电、电网故障、大功率设备的启停等,对充…...

Python包管理工具pip
1、安装pip cmd管理员模式打开控制台 python -m pip install --upgrade pip 2、添加pip环境变量 pip 路径 C:\Users\1\AppData\Local\Programs\Python\Python312\Scripts...

最全国内13家DNS分享 解决网页被恶意跳转或无法打开问题
腾讯 DNS (DNSPod) 腾讯 DNS 是由 DNSPod 提供的公共免费 DNS 服务。DNSPod 已被腾讯收购,现在属于腾讯公司所有。该 DNS 服务稳定性和连通性良好,经测试在海外也可以使用。 DNSPod 提供了 IPv4、IPv6 DNS 和 DoT/DoH 服务。 IPv4 地址: 119.29.29.29…...
最新站长工具箱源码,拥有几百个功能,安装教程
最新站长工具箱源码,拥有几百个功能,安装教程 在 Docker 上运行 docker run -e LAFREGIONCN -e APPLANGzh_CN --name my-miaoda -v ~/.miaoda-docker:/root/.miaoda -d -p 0.0.0.0:39899:39899 codegentoolbox/laftools-linux-x64:latestNOTE: 默认端…...

【算法/训练】:动态规划(线性DP)
一、路径类 1. 字母收集 思路: 1、预处理 对输入的字符矩阵我们按照要求将其转换为数字分数,由于只能往下和往右走,因此走到(i,j)的位置要就是从(i - 1, j)往下走&#…...
计算巨头 Azure、AWS 和 GCP 的比较
云计算领域由三大主要参与者主导:Microsoft Azure、Amazon Web Services (AWS) 和 Google Cloud Platform (GCP)。每个平台都为希望利用云提供基础设施、平台服务等的企业提供强大的功能。在本文中,我们将深入探讨这些平台之间的差异,重点关注…...
Thinkphp5跨域问题常见的处理方法
在ThinkPHP5中,处理跨域问题通常涉及配置中间件或直接在控制器中设置响应头。以下是几种常见的解决跨域问题的方法: 1. 使用中间件处理跨域 你可以创建一个中间件来专门处理跨域请求。这个中间件会检查请求的来源,并设置相应的响应头来允许…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...