linux驱动开发-自旋锁

news/2024/9/19 19:10:30/ 标签: linux, 驱动开发
  • 自旋锁
  • 自旋锁的特点
  • 工作原理
  • 适用场景
  • 优点
  • 缺点
  • API
  • 实现注意事项
  • 调试和分析
  • 最佳实践
  • 自旋锁在中断上下文中的使用
    • 使用自旋锁的最佳做法

自旋锁

自旋锁是一种轻量级的锁机制,用于保护共享资源,它是多线程或多核环境中实现并发访问控制的一种方式。
自旋锁通过忙等待的方式来获取锁,不会使线程进入睡眠状态。

自旋锁的特点

自旋锁针对多核有效

自旋锁获取不到资源的时候会处于自旋锁状态

自旋锁会产生死锁

自旋锁保护的临界区要尽可能的小,在自旋锁保护的临界区中

不能够有延时,耗时,甚至休眠的操作。在自旋锁保护的临界区

中不能够使用copy_to_user/copy_from_user等函数。

自旋锁可以在中断上下文使用

自旋锁在上锁前会关闭抢占

工作原理

自旋锁的基本原理是:当一个线程尝试获取自旋锁时,如果锁已经被其他线程持有,

该线程不会进入休眠,而是会不断循环检查锁的状态。

这种方式称为“自旋”,因为线程在循环中持续占用CPU,直到锁可用为止。

适用场景

自旋锁适用于以下场景:

短暂的临界区:自旋锁适合被持有时间非常短的临界区,因为长时间占用锁会导致等待的线程占用CPU资源,降低系统性能。

多核处理器:在多核处理器中,一个核可以在短时间内等待另一个核释放锁。自旋锁避免了上下文切换的开销,提升效率。

无频繁上下文切换的情境:在某些情况下,线程间的上下文切换本身可能会造成性能损失,而自旋锁可以减少这些切换的需要。

优点

开销小:自旋锁相比较于互斥锁,在获取锁时不需要进行上下文切换,因此开销相对较小。

适用于忙等待:可以高效利用CPU资源,适合短时间持有锁的场景。

缺点

占用CPU:自旋锁会导致等待线程占用CPU,因此在锁被持有较长时间时会浪费CPU资源。

不适合单线程环境:在单核或低并发的环境中,自旋锁通常不如互斥锁高效,因为线程会一直自旋而无法有效利用CPU。

优先级反转问题:在某些情况下,低优先级线程持有自旋锁时,高优先级线程等待获取同样的锁,可能导致高优先级线程的饥饿现象。

API

在Linux内核中,自旋锁的相关API主要包括:

1. 初始化自旋锁DEFINE_SPINLOCK(lock);
DEFINE_SPINLOCK 宏用于静态初始化一个自旋锁。spinlock_t lock;
spin_lock_init(&lock);
spin_lock_init 函数用于动态初始化一个自旋锁。2. 获取自旋锁spin_lock(&lock);
spin_lock 函数用于获取自旋锁。如果锁已经被其他线程持有,当前线程会一直自旋,直到锁被释放。3. 释放自旋锁spin_unlock(&lock);
spin_unlock 函数用于释放自旋锁。4. 获取自旋锁并禁用中断spin_lock_irqsave(&lock, flags);
spin_lock_irqsave 函数用于获取自旋锁,并在获取锁之前保存当前的中断状态,然后禁用中断。flags 用于保存中断状态。5. 释放自旋锁并恢复中断spin_unlock_irqrestore(&lock, flags);
spin_unlock_irqrestore 函数用于释放自旋锁,并在释放锁之后恢复之前保存的中断状态。6. 获取自旋锁并禁用本地CPU的中断spin_lock_irq(&lock);
spin_lock_irq 函数用于获取自旋锁,并在获取锁之前禁用本地CPU的中断。7. 释放自旋锁并启用本地CPU的中断spin_unlock_irq(&lock);
spin_unlock_irq 函数用于释放自旋锁,并在释放锁之后启用本地CPU的中断。8. 获取自旋锁并禁用软中断spin_lock_bh(&lock);
spin_lock_bh 函数用于获取自旋锁,并在获取锁之前禁用软中断。9. 释放自旋锁并启用软中断spin_unlock_bh(&lock);
spin_unlock_bh 函数用于释放自旋锁,并在释放锁之后启用软中断。10. 尝试获取自旋锁spin_trylock(&lock);
spin_trylock 函数用于尝试获取自旋锁。如果锁已经被其他线程持有,该函数会立即返回 false,否则返回 true。11. 尝试获取自旋锁并禁用中断spin_trylock_irqsave(&lock, flags);
spin_trylock_irqsave 函数用于尝试获取自旋锁,并在尝试获取锁之前保存当前的中断状态,然后禁用中断。flags 用于保存中断状态。如果锁已经被其他线程持有,该函数会立即返回 false,否则返回 true。12. 尝试获取自旋锁并禁用本地CPU的中断spin_trylock_irq(&lock);
spin_trylock_irq 函数用于尝试获取自旋锁,并在尝试获取锁之前禁用本地CPU的中断。如果锁已经被其他线程持有,该函数会立即返回 false,否则返回 true。13. 尝试获取自旋锁并禁用软中断spin_trylock_bh(&lock);
spin_trylock_bh 函数用于尝试获取自旋锁,并在尝试获取锁之前禁用软中断。如果锁已经被其他线程持有,该函数会立即返回 false,否则返回 true。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/slab.h>// 定义自旋锁
DEFINE_SPINLOCK(my_lock);// 共享资源
int shared_resource = 0;// 线程函数
void my_thread_func(void *data) {int i;for (i = 0; i < 1000000; i++) {// 获取自旋锁spin_lock(&my_lock);// 访问共享资源shared_resource++;// 释放自旋锁spin_unlock(&my_lock);}
}// 模块初始化函数
static int __init my_spinlock_init(void) {struct task_struct *thread1, *thread2;// 创建两个内核线程thread1 = kthread_run(my_thread_func, NULL, "my_thread1");thread2 = kthread_run(my_thread_func, NULL, "my_thread2");if (IS_ERR(thread1) || IS_ERR(thread2)) {printk(KERN_ERR "my_spinlock: Failed to create kernel threads\n");return -1;}printk(KERN_INFO "my_spinlock: Module initialized\n");return 0;
}// 模块退出函数
static void __exit my_spinlock_exit(void) {printk(KERN_INFO "my_spinlock: Module exited\n");
}module_init(my_spinlock_init);
module_exit(my_spinlock_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("gopher");
MODULE_DESCRIPTION("A simple spinlock example");

实现注意事项

避免过度自旋:

对于可能长时间持有自旋锁的操作,不应使用自旋锁,而应采用互斥锁等其他同步机制。

避免锁嵌套:

如果在持锁状态下再试图获取同一把锁,会导致死锁。设计时应确保自旋锁的获取与释放不应相互嵌套。

优先级反转(Priority Inversion):

使用自旋锁可能会引入优先级反转问题。这是由于低优先级线程持有锁,导致高优先级线程程序被阻塞,进而影响系统整体响应。

自旋锁与中断上下文:

自旋锁不能在中断上下文中持有,尤其是在长时间运行的操作中。若当前上下文为中断处理程序,推荐使用其他机制(如互斥锁)。

调试和分析

检测自旋锁的竞争:

通过监测自旋锁的竞争情况,可以识别系统在并发访问中出现的性能问题。例如,使用dmesg命令可以查看锁的相关统计信息。

自旋锁的调试信息:

在内核调试中,可以通过printk等机制输出自旋锁的获取和释放的相关信息。这有助于检测潜在的死锁和竞争状态

最佳实践

限制自旋次数:

设置自旋的最大次数后自动放弃锁的获取,避免无限自旋,这样更能合理利用CPU。

使用条件变量:

在某些情况下,可以使用条件变量与自旋锁配合,允许更复杂的同步条件。

选择合适的锁:

在适合的场景下使用互斥锁弹性替代自旋锁。互斥锁会在获取锁时睡眠,而不是持续占用CPU。

代码审查:

在代码审查中关注自旋锁的使用,确保其符合上述原则,如确保不会造成优先级反转和死锁等问题。

自旋锁在中断上下文中的使用

自旋锁的可用性:

自旋锁可以在中断上下文中使用,这是因为自旋锁不会让线程进入睡眠状态。因此,中断处理程序可以通过自旋锁来保护共享资源,以防止在中断处理期间发生数据竞态。

小心持锁时间:

在中断上下文中持有自旋锁的时间必须尽可能短。如果在持有自旋锁时执行需要较长时间的操作,会导致性能下降,甚至导致优先级反转。这是因为在一个高优先级的中断处理程序中持有自旋锁,低优先级线程可能无法获取锁,从而影响系统响应。

避免使用容易阻塞的操作:

在中断上下文中,应避免任何可能导致线程阻塞的操作。这意味着在中断上下文中持有自旋锁时,绝对不应该调用会在用户空间进行 I/O 操作的函数(如 copy_to_user 或 copy_from_user)。

使用自旋锁的最佳做法

使用合适的上下文:

一般情况下,尽量避免在中断处理程序中进行复杂的计算或持有自旋锁过长时间。可以将需要的操作简单化,并在必要时使用消息传递或队列系统来处理复杂任务。

限制临界区:

在中断处理程序中持有自旋锁时,只应执行极少量的代码,确保在获取自旋锁后尽快释放它,以提高系统的并发性能。

使用不同的锁机制:

如果在中断上下文中需要长时间处理共享资源,可以考虑使用其他同步机制,比如使用消息队列和工作队列,这样可避免在中断上下文中持有锁。


http://www.ppmy.cn/news/1527731.html

相关文章

TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错

目录 1&#xff0c;前言2&#xff0c;二者关系2.1&#xff0c;使用 3&#xff0c;遇到的问题3.1&#xff0c;TS 中使用 JS 1&#xff0c;前言 通过 Vite 创建的 Vue3 TS 项目&#xff0c;根目录下会有 tsconfig.json 和 tsconfig.node.json 文件&#xff0c;并且存在引用关系…

leetcode:字符串中的第一个唯一字符

#include <unordered_map> class Solution { public:int firstUniqChar(string s) {unordered_map<char, int> HashMap;string::iterator it s.begin();int i 0;//标记元素下标while (it ! s.end())//初始化哈希表{if (HashMap.count(*it) > 0)//原先hash表中…

第十章 【后端】环境准备(10.10)——Nacos

10.10 Nacos 10.10.1 本地安装 下载 下载地址:https://nacos.io/download/nacos-server/ 解压缩 进入 bin 目录 启动(standalone代表着单机模式运行,非集群模式) ./startup.cmd -m standalone注意:PowerShell 下执行 .\startup.cmd -m standalone 命令

撤回仓库的提交

结论先行 未推送提交&#xff1a;可以使用 git reset --soft HEAD~1 或 git reset --hard HEAD~1 来撤回提交&#xff0c;选择保留或丢弃修改。已推送提交&#xff1a;可以使用 git reset --soft HEAD~1 后&#xff0c;通过 git push --force 强制覆盖远程的提交记录。 问题描…

react 组件通讯

组件通讯 组件是独立且封闭的单元&#xff0c;默认情况下&#xff0c;只能使用组件自己的数据。在组件化过程中&#xff0c;我们将一个完整的功能拆分成多个组件&#xff0c;以更好的完成整个应用的功能。而在这个过程中&#xff0c;多个组件之间不可避免的要共享某些数据。为…

东方博宜 24年9月-A组(萌新)- 巧克力

题目描述 假期快要结束了&#xff0c;小 A 打算好好犒劳一下自己&#xff0c;一路小跑来到超市&#xff0c;看到货架上的各种巧克力&#xff0c;都是自己爱吃的&#xff0c;一口气抓了一堆&#xff0c;有黑巧克力&#xff0c;白巧克力&#xff0c;牛奶巧克力&#xff0c;总共 …

【Java】网络编程:TCP_IP协议详解(IP协议数据报文及如何解决IPv4不够的状况)

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 &#x1f354…

Java 中使用 Redis 的几种方式优缺点对比

一、为什么选择 Redis&#xff1f; 在分析 Java 中使用 Redis 的不同方式之前&#xff0c;我们需要了解为什么 Redis 在分布式应用中如此重要。以下是 Redis 在 Java 项目中常见的应用场景&#xff1a; 缓存&#xff1a;通过将热点数据缓存到 Redis&#xff0c;可以减少数据库…

计算机网络 第三章: 点对点协议

文章目录 点对点协议PPP概述PPP的帧格式PPP桢的透明传输PPP帧的差错检测PPP的工作状态 点对点协议PPP概述 点对点协议&#xff08;Point-to-Point Protocol&#xff0c;PPP&#xff09;是目前使用最广泛的点对点数据链路层协议。 点对点协议PPP是因特网工程任务组&#xff08…

什么是蜘蛛池?有什么作用

在网络爬虫的世界里&#xff0c;蜘蛛池&#xff08;Spider Pool&#xff09;是一个专门用于管理和维护大量爬虫的系统。它为爬虫提供了一个集中的工作环境&#xff0c;使得爬虫能够更高效、更稳定地进行数据抓取。本文将探讨蜘蛛池的概念、组成以及它在现代网络爬虫技术中的作用…

CSU18M91四电极测脂模块开发体脂秤方案

一台体脂秤通过测试体重、体脂、BMI、水分等数据并给出相应提示&#xff0c;并且许多人都将体脂检测数据作为身体健康指数衡量标准&#xff0c;辅助用户来关注身体健康&#xff0c;同时可以通过蓝牙与手机APP应用相连&#xff0c;记录日常身体变化情况&#xff0c;根据变化情况…

黑神话悟空mac可以玩吗

黑神话悟空mac上能不能玩对于苹果玩家来说很重要&#xff0c;那么黑神话悟空mac可以玩吗&#xff1f;目前是玩不了了&#xff0c;没有针对ios系统的版本&#xff0c;只能之后在云平台上找找了&#xff0c;大家可以再观望下看看。 黑神话悟空mac可以玩吗 ‌使用CrossOver‌&…

前端面试常见手写题

实现一个new操作符 //实现一个new操作符 function myNew(fn,...args){if(typeof fn ! function) {throw (fn is not a function)}//将对象的原型设置为fn的prototypelet resObject.create(fn.prototype)//使用 apply 执行构造函数 并传入参数 arguments 获取函数的返回值let r…

区块链审计 如何测试solidity的bool值占用几个字节

文章目录 艾里卡的bool类型有多大&#xff1f;代码环节 艾丽卡更精确的测试bool代码环节 bool的gas疑惑&#xff1f; 艾里卡的bool类型有多大&#xff1f; 木森和艾丽卡坐在他们的实验室里&#xff0c;面前摆着一本魔法书和一些奇怪的魔法工具。他们正在进行一项重要的研究——…

Spring Boot-静态资源管理问题

在Spring Boot中&#xff0c;静态资源管理是构建现代Web应用程序时必不可少的一部分。无论是处理静态页面、图片、CSS、JavaScript文件&#xff0c;还是一些自定义文件&#xff0c;正确管理这些资源能够提升用户体验和优化应用的性能。 1. Spring Boot中的静态资源管理概述 S…

RedisTemplate混用带来的序列化问题

最近在工作中发现一个现象&#xff0c;项目中使用了不同的 RedisTemplate 来操作redis&#xff0c;有的同事用默认的 RedisTemplate &#xff0c;有的同事用 StringRedisTemplate。这就导致了我本次遇到的问题&#xff1a; 在一次需求中&#xff0c;我需要从 redis 中取值&…

在单片机中,处于高阻态是什么状态

在单片机&#xff08;微控制器&#xff09;中&#xff0c;高阻态&#xff08;High-Z&#xff0c;High Impedance State&#xff09;是指引脚的电气特性类似于没有连接状态&#xff0c;即该引脚的电流非常小&#xff0c;几乎不对电路产生影响。具体来说&#xff0c;高阻态具有以…

爬虫逆向学习(六):补环境过某数四代

声明&#xff1a;本篇文章内容是整理并分享在学习网上各位大佬的优秀知识后的实战与踩坑记录 引用博客&#xff1a; https://blog.csdn.net/shayuchaor/article/details/103629294 https://blog.csdn.net/qq_36291294/article/details/128600583 https://blog.csdn.net/weixin_…

Spring Cloud Config 配置中心

在java开发中难免会涉及到配置文件&#xff0c;比如连接数据库配置、连接一些中间件配置、一些阈值或开关参数等等。我们一般存放到properties或yml文件中&#xff0c;然后应用部署启动的时候读取这些配置项。在分布式系统中&#xff0c;多个服务需要访问和管理配置。如果每个服…

第十章 【后端】环境准备(10.9)——Navicat

10.9 Navicat Navicat Premium 官网 下载 下载地址:https://www.navicat.com.cn/download/navicat-premium-lite 安装 一路“下一步”即可。 连接 `MySql’