linux c 递归锁的介绍

递归锁的递归特性确实只是对于持有锁的线程。当一个线程获取了递归锁后,它可以多次重复获取该锁,而不会导致自身阻塞或死锁。这是递归锁的重要特点,它允许同一个线程在已经持有锁的情况下,再次获取相同的锁。

然而,对于其他线程,如果该递归锁已经被某个线程持有(即使是持有锁的线程自身多次获取的),那么其他线程在尝试获取该锁时,仍然会被阻塞,直到持有锁的线程进行了相应次数的解锁操作,使得锁完全释放后,其他线程才有机会获取该锁。

递归锁通常应用于递归函数或方法,以及存在嵌套临界区的情况。在这些场景下,同一个线程可能需要在不同的递归层次或嵌套的临界区中多次获取同一个锁。通过使用递归锁,可以确保线程不会因为自身重复获取锁而产生死锁问题。

需要注意的是,使用递归锁时,持有锁的线程必须进行相应次数的解锁操作,以平衡之前的加锁操作。也就是说,对于每次加锁,都需要有一个对应的解锁,只有当解锁次数与加锁次数相等时,锁才会完全释放,其他线程才能获取该锁。如果解锁次数不足或过多,都可能导致死锁或其他同步问题的发生。

如在一个递归函数中,每次递归调用都需要获取相同的锁进行保护,递归锁就可以满足这种需求。而如果使用普通的互斥锁,在同一线程中再次尝试获取已经持有的锁时,就会导致死锁。

PTHREAD_MUTEX_RECURSIVE 是一种递归锁,它允许同一个线程对同一个锁成功获得多次,并通过多次 unlock 解锁。

使用 PTHREAD_MUTEX_RECURSIVE 递归锁的一般步骤如下:

  1. 包含必要的头文件:#include <pthread.h>
  2. 初始化互斥锁属性对象:使用 pthread_mutexattr_init(&attr); 初始化一个互斥锁属性对象 attr
  3. 设置锁的类型为递归锁:通过 pthread_mutexattr_settype(&attr, pthread_mutex_recursive); 将互斥锁的类型设置为递归锁。
  4. 初始化递归锁:使用 pthread_mutex_init(&mutex, &attr); 初始化递归锁 mutex,并关联之前设置好属性的 attr 对象。
  5. 在需要加锁的代码段前加锁:通过 pthread_mutex_lock(&mutex); 进行加锁操作。如果是在同一个线程中且之前已经加过锁,不会产生死锁,而是可以成功再次加锁。
  6. 在相应的代码段结束后解锁:调用 pthread_mutex_unlock(&mutex); 释放锁。需要注意的是,加锁几次就需要解锁几次,才能完全释放该锁,以便其他线程获取该锁。
  7. 不再使用递归锁后,销毁互斥锁:使用 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>// 其余代码...

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

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

相关文章

Zabbix基本介绍

文章目录 一、监控为什么需要监控需要监控什么Zabbix使用场景及系统概述zabbix介绍Zabbix功能Zabbix架构Zabbix术语 二、部署安装编译安装 一、监控 为什么需要监控 监控功能 在需要的时刻&#xff0c;提前预警即将出问题,避免故障发生。实时监控系统和业务,当出问题之后&am…

在本地远程访问云Linux服务器部署的tomcat管理控制台

样例: 我们将创建一个 SSH 隧道&#xff0c;将本地计算机的端口映射到远程服务器的端口,以达到在本地的windows系统中访问云Linux中tomcat的管理控制台的目的 1.打开终端,输入以下字段 ssh -L 8080:localhost:8080 userserver_ip 其中各项代表的值为: -L [local_port]:[remo…

Android11 framework 禁止三方应用通过广播开机自启动-独立方案

之前的文章Android11 framework 禁止三方应用开机自启动记录了我调试Android11应用自启动限制的全过程&#xff0c;但是之前的方案感觉还能再研究&#xff0c;所以有了这一篇文章。 这一篇文章主要探讨Android11上&#xff0c;以广播来进行自启动的应用的限制&#xff0c;极个别…

数据库安全:MySQL安全配置,MySQL安全基线检查加固

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 这一章节我们需…

Java中的字符串类型——String

字符串类型 不可变类型&#xff1a;一旦创建&#xff0c;值就不会改变fianl修饰类不能继承&#xff0c;不能被重写&#xff0c;修饰char类型后&#xff0c;地址不可变&#xff0c;内容可变&#xff0c;没有具体方法修改内容&#xff0c;保证不可变性 常用方法 长度&#xff…

(十七)原生js案例之h5中的几个特性记录

h5 中的新特性 语义化标签增强型表单元素选择器 querySelectorquerySelectorAllgetElementsByClassName class 的操作 classList.addclassList.removeclassList.toggleclassList.containsclassList.replace JSON JSON.stringifyJSON.parseeval 可以解析任何字符串变成 jspares…

配置Linux客户端免密登录服务端Linux主机的root用户

1.安装shh服务 首先安装shh服务&#xff0c;redhat端通过下面代码进行安装服务 sudo yum install sshd sudo yum install openssh-server 2.生成密钥&#xff08;公钥&#xff0b;私钥&#xff09; 执行ssh-keygen命令&#xff0c;会生成id_rsa&#xff08;私钥&#xff0…

【ffmpeg命令入门】再论ffmpeg通用选项

文章目录 前言强制使用特定的文件格式1. 将 MP4 文件转换为 AVI 格式2. 录制音频3. 从摄像头录制视频 指定输入文件覆盖同名文件限制输入/输出文件的时间指定结束点时间主要区别举例说明1. 使用 -t 截取前 10 秒的视频2. 使用 -to 截取到第 10 秒的视频 实际应用中的区别1. 从第…

并发编程--synchronized介绍

1.初步认识synchronized 先来看下利用 synchronized 实现 同步的基 础 &#xff1a; Java 中的每一个 对 象都可以作 为锁 。具体表 现 为 以下 3 种形式。 &#xff1a; 对于普通同步方法&#xff0c; 锁 是当前 实 例 对 象。 对于静 态 同步方法&#xff0c; 锁 是当前 类…

python-首字母移位(PythonTip)

[题目描述] 编写一个程序&#xff0c;将句子中每个单词的首字母移位到下一个单词。定义函数shift_first_letter()&#xff0c;参数为sentence&#xff08;字符串&#xff09;。在函数内&#xff0c;将句子中每个单词的首字母移位到下一个单词。最后一个单词的首字母移位到句子的…

python进阶---闭包与装饰器

一、闭包 在Python中&#xff0c;闭包是指一个函数内部定义的函数&#xff0c;这个内部函数可以访问并修改其外部函数的局部变量&#xff0c;即使外部函数已经执行完毕。闭包可以通过多层函数嵌套来实现。 闭包的三要素&#xff1a; 1、外部函数嵌套内部函数 2、外部函数返回内…

SQL 注入漏洞详解 - Union 注入

1)漏洞简介 SQL 注入简介 SQL 注入 即是指 Web 应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在 Web 应用程序中事先定义好的查询语句的结尾上添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,…

罗技 F710 无线游戏手柄用户指南

罗技 F710 无线游戏手柄用户指南 Gamepad F710功能系统XInput 游戏DirectInput的 游戏1.左键/触发器按钮为数字&#xff1b; 触发器是模拟的按钮和触发器是数字的和可编程的*2.右键/触发器按钮为数字&#xff1b; 触发器是模拟的按钮和触发器是数字的和可编程的*3.方向键8 向方…

记录|C#+winform创建扁平化风格界面

本项目的C#内容是自己跟做的&#xff0c;自己做的内容已经打包&#xff0c;可以通过自己跟做写的Dashboard界面&#xff0c;C#下的winform模式下载获得&#xff0c;但是需要花费3个积分 目录 前言一、左边设置和步骤界面步骤Step1.Step2.Step3.Step4Step5 二、右边属性和步骤属…

【BUG】已解决:ModuleNotFoundError: No module named ‘requests‘

ModuleNotFoundError: No module named ‘requests‘ 目录 ModuleNotFoundError: No module named ‘requests‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&a…

Django已经登录但是还是提示登录

问题描述 在使用 Django 开发网站时&#xff0c;你可能会遇到一个问题&#xff1a;当用户在访问网站时&#xff0c;如果 URL 从 https://200sm.com/chat/ 切换到 https://www.200sm.com/chat/&#xff0c;用户可能会被要求重新登录或遇到其他验证问题。这是因为 Django 默认情…

Python怎样读取URL生成PDF

1. 安装依赖的exe 需要在这个网址&#xff0c;安装一个exe包&#xff0c;地址&#xff1a;https://wkhtmltopdf.org/ 进入网址后&#xff0c;点这个位置&#xff1a; 选择一个你的操作系统的下载链接&#xff1a; 安装后的exe文件&#xff1a; C:\Program Files\wkhtmltopdf…

vue3.2使用@wangeditor/editor-for-vue实现富文本编辑器,后端使用thinkphp上传图片

Vue 组件代码 npm i wangeditor/editor-for-vue<template><div style"border: 1px solid #ccc;height:600px;"><Toolbar style"border-bottom: 1px solid #ccc" :editor"editorRef" :defaultConfig"toolbarConfig" :m…

记录解决springboot项目上传图片到本地,在html里不能回显的问题

项目场景&#xff1a; 项目场景&#xff1a;在我的博客系统里&#xff1a;有个相册模块&#xff1a;需要把图片上传到项目里&#xff0c;在html页面上显示 解决方案 1.建一个文件夹 例如在windows系统下。可以在项目根目录下建个photos文件夹&#xff0c;把上传的图片文件…

n9.Nginx 自定义访问日志

Nginx 自定义访问日志 访问日志是记录客户端即用户的具体请求内容信息&#xff0c;而在全局配置模块中的error_log是记录nginx服务 器运行时的日志保存路径和记录日志的level&#xff0c;因此两者是不同的&#xff0c;而且Nginx的错误日志一般只有一 个&#xff0c;但是访问日…