linux RT-Preempt spin lock实现

news2025/1/11 15:25:57

一、spin_lock概述

Spinlock是linux内核中常用的一种互斥锁机制,和mutex不同,当无法持锁进入临界区的时候,当前执行线索不会阻塞,而是不断的自旋等待该锁释放。正因为如此,自旋锁也是可以用在中断上下文的。也正是因为自旋,临界区的代码要求尽量的精简,否则在高竞争场景下会浪费宝贵的CPU资源。

1. spin lock 的发展

(1) TAS和CAS

硬件对同步的支持-TAS和CAS指令 - 元思 - 博客园

锁只有一个原子变量,通过原子指令来修改自旋锁的状态(locked、unlocked)。问题是没有公平可言,无法让等待最长的那个任务优先拿到锁,为了解决这个问题引入了ticket spinlock。

610c9a3e1aa93e6436db6ece3f4163d8.png

如果thread4当前持锁,同一个cluster中的cpu7上的thread7和另外一个cluster中的thread0都在自旋等待锁的释放。当thread4释放锁的时候,由于cpu7和cpu4的拓扑距离更近,thread7会有更高概率可以抢到自旋锁,从而产生了不公平现象。

(2) ticket spinlock

类似排队叫号,只有任务手中事先领取的号和被叫到的号相等时才能持锁进入临界区。这解决了不公平的问题。但是出现叫号时,所有等待的任务所在的cpu都要读取内存,刷新对应的cache line,而只有获取锁的那个任务所在的cpu对cache line 的刷新才是有意义的,锁争抢的越激烈,无谓的开销也就越大。

但是这种自旋锁在持锁失败的时候会对自旋锁状态数据next成员进行++操作,当CPU数据巨大并且竞争激烈的时候,自旋锁状态数据对应的cacheline会在不同cpu上跳来跳去,从而对性能产生影响,

(3) MCS Lock

在ticket spinlock的基础上做一定的修改,让多个CPU不再等待同一个spinlock变量,而是基于各自的per-CPU的变量进行等待,那么每个CPU平时只需要查询自己对应的这个变量所在的本地cache line,仅在这个变量发生变化的时候,才需要读取内存和刷新这条cache line,这样就可以解决上述问题。要实现类似这样的spinlock的分身,其中的一种方法就是使用MCS lock。试图获取一个spinlock的每个CPU,都有一份自己的MCS lock。

(4) qspinlock

相比起Linux中只占4个字节的ticket spinlock,MCS lock多了一个指针,要多占4(或者8)个字节,消耗的存储空间是原来的2-3倍。qspinlock的首要目标就是改进原生的MCS lock结构体,尽量将原生MCS lock要包含的内容塞进4字节的空间里。

如果只有1个或2个CPU试图获取锁,那么只需要一个4字节的qspinlock就可以了,其所占内存的大小和ticket spinlock一样。当有3个以上的CPU试图获取锁,需要一个qspinlock加上(N-2)个MCS node。

qspinlock中加入”pending”位域,如果是两个CPU试图获取锁,那么第二个CPU只需要简单地设置”pending”为1,而不用另起炉灶创建一个MCS node。

试图加锁的CPU数目超过3个是小概率事件,但一旦发生,使用ticket spinlock机制就会造成多个CPU的cache line无谓刷新的问题,而qspinlock可以利用MCS node队列来解决这个问题。

可见,使用qspinlock机制来实现spinlock,具有很好的可扩展性,也就是无论当前锁的争抢程度如何,性能都可以得到保证。

2. spin lock 的命令规范

(1)spinlock,对于没有打上Linux-RT(实时Linux)的patch的系统,spin_lock只是简单地调用raw_spin_lock,实际上他们是完全一样的;如果打上这个patch之后,spin_lock会使用信号量完成临界区的保护工作,带来的好处是同一个CPU可以有多个临界区同时工作,而原有的体系因为禁止抢占的原因,一旦进入临界区,其他临界区就无法运行,新的体系在允许使用同一个临界区的其他进程进行休眠等待,而不是强占着CPU进行自旋操作。

(2)raw_spinlock,即便是配置了PREEMPT_RT也要顽强的spin

(3)arch_spinlock,spin lock是和architecture相关的,arch_spinlock是architecture相关的实现

对于UP平台,所有的arch_spinlock_t都是一样的,定义如下:

typedef struct { } arch_spinlock_t;

什么都没有,一切都是空啊。当然,这也符合前面的分析,对于UP,即便是打开的preempt选项,所谓的spin lock也不过就是disable preempt而已,不需定义什么spin lock的变量。

对于SMP平台,这和arch相关,我们在下一节描述。

二、代码结构

最上层是通用自旋锁代码(体系结构无关,平台无关),这一层的代码提供了两种接口:spinlock接口和raw spinlock接口。在没有配置PREEMPT_RT情况下,spinlock接口和raw spinlock接口是一毛一样的。如果配置了PREEMPT_RT,spinlock接口走rt spinlock,底层是基于rtmutex的。也就是说这时候的spinlock不再禁止抢占,不再自旋等待,而是使用了支持PI的睡眠锁来实现,因此有了更好的实时性。而raw spinlock接口即便在配置了PREEMPT_RT下仍然保持传统自旋锁特性。

中间一层是区分SMP和UP的,在SMP和UP上,自旋锁的实现是不一样的。对于UP,自旋没有意义,因此spinlock的上锁和放锁操作退化为preempt disable和enable。SMP平台上,除了抢占操作之外还有正常自旋锁的逻辑,具体如何实现自旋锁逻辑是和底层的CPU architecture相关的,后面我们会详细描述。

最底层的代码是体系结构相关的代码,ARM64上,目前采用是qspinlock。和体系结构无关的Qspinlock代码抽象在qspinlock.c文件中,也就是本文重点要描述的内容。

在2024年9月的欧洲开源峰会上,Linux创始人Linus Torvalds宣布,“PREEMPT_RT”(实时Linux)补丁已被正式合并进Linux主线内核。 从Linux 6.12版本起,所有发行版将内置实时Linux代码,进一步拓宽Linux在任务关键型设备和工业硬件上的应用。

入口:

先看看linux rt spin lock的结构体:spinlock_types.h - include/linux/spinlock_types.h - Linux source code v6.13-rc3 - Bootlin Elixir Cross Referencer

#include <linux/rtmutex.h>

typedef struct spinlock {
	struct rt_mutex_base	lock;
} spinlock_t;


// include/linux/rtmutex.h
struct rt_mutex_base {
	raw_spinlock_t		wait_lock;
	struct rb_root_cached   waiters;
	struct task_struct	*owner;
};

从上述实现可以看出,rt spin lock的底层实现是支持优先级继承的rt mutex

// include/linux/spinlock_rt.h

static __always_inline void spin_lock(spinlock_t *lock)
{
	rt_spin_lock(lock);
}


// kernel/locking/spinlock_rt.c
void __sched rt_spin_lock(spinlock_t *lock) __acquires(RCU)
{
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
	__rt_spin_lock(lock);
}


static __always_inline void __rt_spin_lock(spinlock_t *lock)
{
	rtlock_might_resched();
	rtlock_lock(&lock->lock);
	rcu_read_lock();
	migrate_disable();
}

static __always_inline void rtlock_lock(struct rt_mutex_base *rtm)
{
	lockdep_assert(!current->pi_blocked_on);

	if (unlikely(!rt_mutex_cmpxchg_acquire(rtm, NULL, current)))
		rtlock_slowlock(rtm);
}

https://elixir.bootlin.com/linux/v6.13-rc3/source/kernel/locking/rtmutex.c#L1875


static __always_inline void __sched rtlock_slowlock(struct rt_mutex_base *lock)
{
	unsigned long flags;
	DEFINE_WAKE_Q(wake_q);

	raw_spin_lock_irqsave(&lock->wait_lock, flags);
	rtlock_slowlock_locked(lock, &wake_q);
	preempt_disable();
	raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
	wake_up_q(&wake_q);
	preempt_enable();
}

自旋锁spin_lock和raw_spin_lock_raw spin log-CSDN博客

linux 之 mutex、rt_mutex、spinlock_t 的实时性补丁分析_linux rt补丁中断能达到多少-CSDN博客

Linux并发与同步专题 (2)spinlock - ArnoldLu - 博客园

Linux内核同步 - spin_lock - AlanTu - 博客园

Linux内核机制—spin_lock - Hello-World3 - 博客园

自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析 - 裸睡的猪 - 博客园

自旋锁探秘-CSDN博客

spinlock.h - include/linux/spinlock.h - Linux source code v5.4.90 - Bootlin Elixir Cross Referencer

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

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

相关文章

Ubuntu 22.04 桥接配置

1. 网卡配置文件备份 sudo cp /etc/netplan/01-network-manager-all.yaml /etc/netplan/01-network-manager-all.yaml.bak 1.1 静态ip配置 1.1.3 解释 network: version: 2 ethernets: # 网卡名称 使用ifconfig查看 ens33: dhcp4: false dhcp6: false …

PHP多功能投票小程序源码

多功能投票小程序&#xff1a;全方位打造专属投票盛宴的得力助手 &#x1f389; &#x1f527; 基于先进的ThinkPHP框架与Uniapp技术深度融合&#xff0c;我们匠心独运&#xff0c;精心雕琢出一款功能全面、操作便捷的投票小程序&#xff0c;旨在为您带来前所未有的投票体验。…

[fastadmin] 第三十四篇 FastAdmin 商城模块标签使用详解

FastAdmin 商城模块标签使用详解 一、标签基本语法 1.1 基础语法格式 {shop:goodslist flag"参数值" id"变量名" row"数量"}<!-- 循环内容 --> {/shop:goodslist}1.2 常用参数说明 flag: 商品标记筛选id: 循环变量名row: 显示数量 1.…

二维数组-

定义&#xff1a;二维数组本质上也就是一维数组&#xff0c;只不过每个元素又是一个一维数组 基本语法&#xff1a; 数据类型[][] 数组名称 new 数据类型 [行数][列数] {}初始化数据; 示例&#xff1a; public class Test {public static void main(String[] args) {int[]…

软件测试预备知识④—NTFS权限管理、磁盘配额与文件共享

在软件测试的实际环境搭建与管理过程中&#xff0c;了解和掌握NTFS权限管理、磁盘配额以及文件共享等知识至关重要。这些功能不仅影响系统的安全性和稳定性&#xff0c;还对测试数据的存储、访问以及多用户协作测试有着深远的影响。 一、NTFS权限管理 1.1 NTFS简介 NTFS&am…

自动控制原理初识

文章目录 1.引言2.自动控制原理2.1方框图的案例2.2方框图里面的相关符号2.3闭环控制系统的特点2.4三种基础控制方式2.5对于控制系统的基本要求2.6自动控制原理的体系架构 3.控制系统的数学模型3.1为什么建模3.2建模的方法3.3什么是线性系统3.4线性or非线性系统判断3.5时变or定常…

计算机网络(二)——物理层和数据链路层

一、物理层 1.作用 实现相信计算机节点之间比特流的透明传输&#xff0c;尽可能屏蔽具体传输介质和物理设备的差异。 2.数据传输单位 比特。 3.相关通信概念 ①信源和信宿&#xff1a;即信号的发送方和接收方。 ②数据&#xff1a;即信息的实体&#xff0c;比如图像、视频等&am…

Linux_进程间通信_共享内存

什么是共享内存&#xff1f; 对于两个进程&#xff0c;通过在内存开辟一块空间&#xff08;操作系统开辟的&#xff09;&#xff0c;进程的虚拟地址通过页表映射到对应的共享内存空间中&#xff0c;进而实现通信&#xff1b;物理内存中的这块空间&#xff0c;就叫做共享内存。…

【linux系统】mysql 数据库迁移至新服务器

文章目录 前言一、新服务器停止数据库服务&#x1f6d1;二、旧服务器打包数据库的data目录&#x1f9f3;三、进入新服务器中打包整个数据库的 data 目录&#xff08;备份&#xff09;四、在新服务器中解压旧服务器打包数据库的 data 目录到数据库data 目录中五、修改新数据库 m…

【数据结构:前缀树Trie】

目录 前言前缀树介绍和应用一、前缀树的定义前缀树的问题和思考前缀树的映射思想前缀树三大性质 二.前缀树节点结构三. 前缀树接口介绍和实现四个接口API1. insert(String word)2. search(String word)3. startsWith(String pre)4. delete(String word) API实现1. 查询操作sear…

数据库高安全—角色权限:权限管理权限检查

目录 3.3 权限管理 3.4 权限检查 书接上文数据库高安全—角色权限&#xff1a;角色创建角色管理&#xff0c;从角色创建和角色管理两方面对高斯数据库的角色权限进行了介绍&#xff0c;本篇将从权限管理和权限检查方面继续解读高斯数据库的角色权限。 3.3 权限管理 &#x…

数据集-目标检测系列- 石榴 检测数据集 pomegranate >> DataBall

数据集-目标检测系列- 石榴 检测数据集 pomegranate >> DataBall DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(fre…

搭建一个本地轻量级且好用的学习TypeScript语言的环境

需求说明 虽然 TypeScript 的在线 Playground 很方便 https://www.tslang.com.cn/play/&#xff0c;但毕竟是在浏览器中使用&#xff0c;没有本地的 IDE 那么顺手。所以我想搭建一个本地类似 Playground 的环境&#xff0c;这样在学习 TypeScript 的过程中&#xff0c;可以更方…

项目管理之引论

在当今这个快速变化、竞争激烈的商业环境中&#xff0c;项目管理已经成为组织实现目标、提升竞争力的关键手段。无论是企业的新产品研发、建筑项目的施工&#xff0c;还是政府部门的公共服务项目推进&#xff0c;都离不开有效的项目管理。以下是我对项目管理的一些初步见解和认…

20250109使用M6000显卡在Ubuntu20.04.6下跑whisper来识别中英文字幕

20250109使用M6000显卡在Ubuntu20.04.6下跑whisper来识别中英文字幕 2025/1/9 20:57 https://blog.csdn.net/wb4916/article/details/144541848 20241217使用M6000显卡在WIN10下跑whisper来识别中英文字幕 步骤&#xff1a; 1、在NVIDIA的官网下载并安装M6000显卡在WIN10下的最…

Windows service运行Django项目

系统&#xff1a;Windows Service 软件&#xff1a;nssm&#xff0c;nginx 配置Django项目 1、把Django项目的静态文件整理到staticfiles文件夹中 注&#xff1a;settings中的设置 STATIC_URL /static/ STATIC_ROOT os.path.join(BASE_DIR, staticfiles/) STATICFILES_DI…

关于物联网的基础知识(二)——物联网体系结构分层

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于物联网的基础知识&#xff08;二&a…

【C++】22.AVL树实现

文章目录 1. AVL的概念AVL树的逻辑理解四种形式1. LL型&#xff08;左孩子的左子树上出现节点使结点失衡&#xff09;2. RR型&#xff08;右孩子的右子树上出现节点使结点失衡&#xff09;3. LR型&#xff08;左孩子的右子树上出现节点使结点失衡&#xff09;4. RL型&#xff0…

php文件包含漏洞

基本 相关函数 php中引发文件包含漏洞的通常是以下四个函数&#xff1a; include()include_once()require()require_once() reuqire() 如果在包含的过程中有错&#xff0c;比如文件不存在等&#xff0c;则会直接退出&#xff0c;不执行后续语句。 include() 如果出错的话&a…

ELK实战(最详细)

一、什么是ELK ELK是三个产品的简称&#xff1a;ElasticSearch(简称ES) 、Logstash 、Kibana 。其中&#xff1a; ElasticSearch&#xff1a;是一个开源分布式搜索引擎Logstash &#xff1a;是一个数据收集引擎&#xff0c;支持日志搜集、分析、过滤&#xff0c;支持大量数据…