linux 互斥锁

news2024/11/7 1:41:27

首先是概念

互斥锁是可以休眠的。

所以不能在中断中使用,

在中断中只能使用 自旋锁。

然后是 函数:

然后是 open 如果以 NONBLOCK 打开, 遇到 互斥锁怎么办?

总结一下:

  1 open()  函数的 阻塞与不阻塞的标志, 还是要看驱动怎么处理。

2 如果 open 是非阻塞打开的,但是 驱动中 的open 函数, 是 mutex_lock() 那么依然是 阻塞的。

3 驱动中可以 依据 应用的 阻塞与非阻塞的关键字 进行 区别处理。      

然后是一个应用的举例。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/delay.h>

static DEFINE_MUTEX(my_mutex);  // 定义互斥体
static int shared_resource = 0;  // 共享资源

// 修改共享资源的函数
static void modify_shared_resource(void)
{
    mutex_lock(&my_mutex);  // 获取互斥体

    // 临界区:对共享资源进行修改
    printk(KERN_INFO "Modifying shared resource\n");
    shared_resource++;
    printk(KERN_INFO "Shared resource value: %d\n", shared_resource);

    // 模拟一些耗时操作
    mdelay(100);  // 100 毫秒的延迟

    mutex_unlock(&my_mutex);  // 释放互斥体
}

static int __init mutex_example_init(void)
{
    printk(KERN_INFO "Mutex example module loaded\n");

    // 模拟多个线程对共享资源的访问
    modify_shared_resource();
    modify_shared_resource();

    return 0;
}

static void __exit mutex_example_exit(void)
{
    printk(KERN_INFO "Mutex example module unloaded\n");
}

module_init(mutex_example_init);
module_exit(mutex_example_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Example Author");
MODULE_DESCRIPTION("A simple example of mutex usage in Linux kernel");

然后是应用层的 Mutex 与 驱动的mutex 的区别。

我在网上见到一个这个函数,

pthread_mutex_lock(&mutex);

那么与驱动的 mutex有什么区别呢?

总结: 就是一个是 posix 的,一个是内核提供的,感觉没有什么区别。

然后是 互斥锁的分析。

直接抄过来 AI解释。

// 定义一个静态内联函数,用于获取互斥锁,包含复杂的参数  
static __always_inline int __sched  
__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,  
		    struct lockdep_map *nest_lock, unsigned long ip,  
		    struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)  
{  
	// 定义一个互斥锁等待者结构体  
	struct mutex_waiter waiter;  
	bool first = false; // 标记当前等待者是否是等待队列中的第一个  
	struct ww_mutex *ww; // 指向ww_mutex的指针  
	int ret; // 函数返回值  
   
	// 表明该函数可能会睡眠(即可能会阻塞)  
	might_sleep();  
   
	// 将lock指针转换为ww_mutex指针  
	ww = container_of(lock, struct ww_mutex, base);  
	// 如果使用ww_ctx且ww_ctx非空  
	if (use_ww_ctx && ww_ctx) {  
		// 如果ww_ctx与ww的当前上下文相同,则直接返回-EALREADY  
		if (unlikely(ww_ctx == READ_ONCE(ww->ctx)))  
			return -EALREADY;  
   
		// 如果ww_ctx没有获取任何锁,则重置其wounded标志  
		if (ww_ctx->acquired == 0)  
			ww_ctx->wounded = 0;  
	}  
   
	// 禁用抢占  
	preempt_disable();  
	// 记录锁依赖关系  
	mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);  
   
	// 尝试快速获取锁或乐观自旋获取锁  
	if (__mutex_trylock(lock) ||  
	    mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) {  
		// 成功获取锁  
		lock_acquired(&lock->dep_map, ip);  
		if (use_ww_ctx && ww_ctx)  
			ww_mutex_set_context_fastpath(ww, ww_ctx);  
		preempt_enable(); // 重新启用抢占  
		return 0;  
	}  
   
	// 获取锁的等待锁  
	spin_lock(&lock->wait_lock);  
	// 再次尝试获取锁  
	if (__mutex_trylock(lock)) {  
		if (use_ww_ctx && ww_ctx)  
			__ww_mutex_check_waiters(lock, ww_ctx);  
		goto skip_wait; // 跳转到跳过等待的代码段  
	}  
   
	// 调试信息记录  
	debug_mutex_lock_common(lock, &waiter);  
   
	// 记录锁竞争情况  
	lock_contended(&lock->dep_map, ip);  
   
	// 根据是否使用ww_ctx,将等待者添加到等待队列的不同位置  
	if (!use_ww_ctx) {  
		__mutex_add_waiter(lock, &waiter, &lock->wait_list);  
#ifdef CONFIG_DEBUG_MUTEXES  
		waiter.ww_ctx = MUTEX_POISON_WW_CTX; // 调试用,标记ww_ctx为无效  
#endif  
	} else {  
		ret = __ww_mutex_add_waiter(&waiter, lock, ww_ctx);  
		if (ret)  
			goto err_early_kill; // 如果添加失败,则跳转到错误处理  
		waiter.ww_ctx = ww_ctx; // 设置等待者的ww_ctx  
	}  
   
	waiter.task = current; // 设置等待者的任务为当前任务  
   
	// 设置当前任务的状态为指定的state(通常是TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE)  
	set_current_state(state);  
	for (;;) { // 无限循环,直到成功获取锁或发生错误  
		if (__mutex_trylock(lock))  
			goto acquired; // 成功获取锁,跳转到获取锁后的处理代码  
   
		// 检查当前任务是否有待处理的信号  
		if (unlikely(signal_pending_state(state, current))) {  
			ret = -EINTR; // 如果有信号,则返回-EINTR  
			goto err; // 跳转到错误处理  
		}  
   
		if (use_ww_ctx && ww_ctx) {  
			ret = __ww_mutex_check_kill(lock, &waiter, ww_ctx);  
			if (ret)  
				goto err; // 如果需要被杀掉,则跳转到错误处理  
		}  
   
		// 释放等待锁,让出CPU  
		spin_unlock(&lock->wait_lock);  
		schedule_preempt_disabled();  
   
		// 如果是ww_mutex或第一次检查,则更新first标志,并可能设置MUTEX_FLAG_HANDOFF标志  
		if ((use_ww_ctx && ww_ctx) || !first) {  
			first = __mutex_waiter_is_first(lock, &waiter);  
			if (first)  
				__mutex_set_flag(lock, MUTEX_FLAG_HANDOFF);  
		}  
   
		// 重新设置任务状态,并尝试再次获取锁或自旋等待  
		set_current_state(state);  
		if (__mutex_trylock(lock) ||  
		    (first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, &waiter)))  
			break; // 如果成功获取锁,则跳出循环  
   
		// 获取等待锁,准备下一次循环  
		spin_lock(&lock->wait_lock);  
	}  
	spin_lock(&lock->wait_lock); // 确保在修改锁状态前持有等待锁  
acquired:  
	__set_current_state(TASK_RUNNING); // 设置任务状态为运行  
   
	if (use_ww_ctx && ww_ctx) {  
		// 如果是ww_mutex且不是第一个等待者,则检查等待队列中的其他等待者  
		if (!ww_ctx->is_wait_die &&  
		    !__mutex_waiter_is_first(lock, &waiter))  
			__ww_mutex_check_waiters(lock, ww_ctx);  
	}  
   
	// 从等待队列中移除等待者,并清理相关状态  
	mutex_remove_waiter(lock, &waiter, current);  
	if (likely(list_empty(&lock->wait_list)))  
		__mutex_clear_flag(lock, MUTEX_FLAGS);  
   
	debug_mutex_free_waiter(&waiter); // 释放等待者相关的调试信息  
   
skip_wait:  
	// 记录锁获取成功  
	lock_acquired(&lock->dep_map, ip);  
   
	if (use_ww_ctx && ww_ctx)  
		ww_mutex_lock_acquired(ww, ww_ctx); // 如果是ww_mutex,则记录锁获取成功  
   
	spin_unlock(&lock->wait_lock); // 释放等待锁  
	preempt_enable(); // 重新启用抢占  
	return 0; // 成功获取锁  
   
err:  
	__set_current_state(TASK_RUNNING); // 设置任务状态为运行  
	mutex_remove_waiter(lock, &waiter, current); // 从等待队列中移除等待者  
err_early_kill:  
	spin_unlock(&lock->wait_lock); // 释放等待锁  
	debug_mutex_free_waiter(&waiter); // 释放等待者相关的调试信息  
	mutex_release(&lock->dep_map, 1, ip); // 记录锁释放  
	preempt_enable(); // 重新启用抢占  
	return ret; // 返回错误码  
}

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

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

相关文章

第72期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

[ 应急响应靶场实战 ] VMware 搭建win server 2012应急响应靶机 攻击者获取服务器权限上传恶意病毒 防守方人员应急响应并溯源

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

Linux运维高手工具全集及功能分类:20+必备神器

文章目录 Linux运维高手工具全集及功能分类&#xff1a;20必备神器一、系统管理与配置1.1 Shell1.2 Ansible1.3 Puppet1.4 Chef 二、监控与告警2.1 Prometheus2.2 Grafana2.3 Zabbix2.4 Nagios2.5 ELK Stack&#xff08;Elasticsearch, Logstash, Kibana&#xff09; 三、容器与…

安卓APP开发中,如何使用加密芯片?

加密芯片是一种专门设计用于保护信息安全的硬件设备&#xff0c;它通过内置的加密算法对数据进行加密和解密&#xff0c;以防止敏感数据被窃取或篡改。如下图HD-RK3568-IOT工控板&#xff0c;搭载ATSHA204A加密芯片&#xff0c;常用于有安全防护要求的工商业场景&#xff0c;下…

什么是x86架构,什么是arm架构

什么是 x86 架构&#xff1f; x86 架构是一种经典的指令集架构&#xff08;ISA&#xff09;&#xff0c;最早由英特尔在 1978 年推出&#xff0c;主要用于 PC、服务器等领域。 它是一种复杂指令集计算&#xff08;CISC&#xff09;架构&#xff0c;支持大量的复杂指令和操作&…

知识分享 | SNP检测试剂盒开发注意事项及启衡星CDMO案例分享

一、SNP检测方法 常规有阵列的杂交、qPCR和测序等多种方法&#xff0c;其中基于qPCR方法的SNP检测试剂盒因具有快速、简便的优势&#xff0c;已有大量检测试剂盒上市。如&#xff1a;人CYP2C9和VKORC1基因检测试剂盒、人类SLCO1B1和ApoE基因分型检测试剂盒、人ADRB1&#xff0…

详解varint,zigzag编码, 以及在Go标准库中的实现

文章目录 为啥需要varint编码为啥需要zigzag编码varint编码解码 zigzag编码解码 局限性 为啥需要varint编码 当我们用定长数字类型int32来表示整数时&#xff0c;为了传输一个整数1&#xff0c;我们需要传输00000000 00000000 00000000 00000001 32 个 bits&#xff0c;而有价…

又一部神作登场,MTC高分8.8认证,堪称年度佳片

威尼斯电影节上&#xff0c;布拉迪科贝特导演的新作《粗野派》大放异彩。这部电影&#xff0c;不仅在现场收获了观众的真诚掌声&#xff0c;甚至被不少专业影评人评为“2024年度最佳电影”&#xff0c;而这个评价背后&#xff0c;是一部作品真正打动人心的力量。 布拉迪科贝特&…

低代码平台如何通过AI赋能,实现更智能的业务自动化?

引言 随着数字化转型的加速推进&#xff0c;企业在日常运营中面临的业务复杂性与日俱增。如何快速响应市场需求&#xff0c;优化流程&#xff0c;并降低开发成本&#xff0c;成为各行业共同关注的核心问题。低代码平台作为一种能够快速构建应用程序的工具&#xff0c;因其可视化…

进程、孤儿进程、僵尸进程、fork、wait简介

进程相关概念 程序和进程 程序&#xff1a;是指编译好的二进制文件&#xff0c;在磁盘上&#xff0c;占用磁盘空间, 是一个静态的概念. 进程&#xff1a;一个启动的程序&#xff0c; 进程占用的是系统资源&#xff0c;如&#xff1a;物理内存&#xff0c;CPU&#xff0c;终端等…

已解决:VS2022一直显示编译中但无法运行的情况

本问题已得到解决&#xff0c;请看以下小结&#xff1a; 关于《VS2022一直显示编译中但无法运行的情况》的解决方案 记录备注报错时间2024年报错版本VS2022报错复现突然VS2022不能启动&#xff0c;一直显示编译中&#xff0c;取消重试无效&#xff0c;重新生成解决方案无效报错…

12. MapReduce全局计数器

一. 计数器概述 在执行MapReduce程序时&#xff0c;控制台的输出中一般会包含如下内容。 这些输出就是MapReduce的全局计数器的输出信息。计数器是用来记录job的执行进度和状态的&#xff0c;它的作用可以理解为日志&#xff0c;方便用户了解任务的执行状况&#xff0c;辅助…

Springboot集成阿里云通义千问(灵积模型)

我这里集成后&#xff0c;做成了一个工具jar包&#xff0c;如果有不同方式的&#xff0c;欢迎大家讨论&#xff0c;共同进步。 集成限制&#xff1a; 1、灵积模型有QPM(QPS)限制&#xff0c;每个模型不一样&#xff0c;需要根据每个模型适配 集成开发思路&#xff1a; 因有…

今年双11,拼多多吹“新”风

文 | 螳螂观察 作者 | 陈小江 这届双11真变了。 以前提到双11&#xff0c;不管平台、商家全都盯着价格。但今年不一样。这届双11给出了新解法——平台不再把“我的价格比你低”挂在嘴边&#xff0c;转而更关心消费者体验和为商家减负。 双11这艘大船&#xff0c;在航行到第…

005 IP地址的分类

拓扑结构如下 两台主机处于同一个网关下&#xff0c;通过ping命令检测&#xff0c;可以连通 &nbps; 拓扑结构如下 使用ping 检查两台电脑是否相通, 因为网络号不一样&#xff0c;表示两台电脑不在同一个网络&#xff0c;因此无法连通 拓扑结构如下 不在同一网络的PC要相…

记本地第一次运行seatunnel示例项目

前置 静态源码编译通过&#xff1a;https://blog.csdn.net/u011924665/article/details/143372464 参考 seatunnel官方的开发环境搭建文档&#xff1a;https://seatunnel.incubator.apache.org/zh-CN/docs/2.3.5/contribution/setup 安装scala 下载scala 去官网下载&…

《暗河传》 顺利杀青,苏棋演绎“千面鬼”慕婴引期待

近日&#xff0c;由龚俊、彭小苒、常华森、杨雨潼等一众优秀演员出演的古装武侠剧《暗河传》顺利杀青&#xff0c;00后小花苏棋饰演的“千面鬼”慕婴一角也收获了许多关注的目光。 《暗河传》凭借其精彩的剧情和庞大的粉丝基础&#xff0c;自开拍起便备受关注。在剧中&#xff…

推荐一个没有广告,可以白嫖的产品宣传册转换翻页电子书的网站

​随着数字化时代的到来&#xff0c;传统的纸质宣传册逐渐被电子书所取代。为了满足企业和个人对高效、便捷的电子宣传册制作需求&#xff0c;许多在线平台应运而生。今天&#xff0c;就让我为您推荐一个无需广告干扰、完全免费使用的在线宣传册转换翻页电子书网站——【FLBOOK…

QT 从ttf文件中读取图标

最近在做项目时&#xff0c;遇到需要显示一些特殊字符的需求&#xff0c;这些特殊字符无法从键盘敲出来&#xff0c;于是乎&#xff0c;发现可以从字体库文件ttf中读取显示。 参考博客&#xff1a;QT 图标字体类IconHelper封装支持Font Awesome 5-CSDN博客 该博客封装的很不错…

[Linux关键词]unmask,mv,dev/pts,stdin stdout stderr,echo

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;大大会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…