首页 > 其他分享 >自旋锁探秘

自旋锁探秘

时间:2023-10-17 23:01:51浏览次数:39  
标签:RT 缓存 优先级 PREEMPT 自旋 探秘 CPU

spinlockmutex

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

mutex

Mutex(互斥锁)是一种在多线程编程中常用的同步机制,用于控制多个线程对共享资源的访问,以避免并发冲突。Mutex 简称互斥量,其目的是确保在任何给定时刻只有一个线程可以访问共享资源,从而防止数据竞争和不确定性行为。

临界区

在并发编程中,临界区(Critical Section)是指一段代码或代码块,其中包含了对共享资源的访问或修改操作。这个临界区被保护,以确保在任何给定时刻只有一个线程可以访问它,以避免并发冲突和数据竞争。

这里临界区指的是那些被自旋锁保护的代码端。当一个现场获得了自旋锁并进入临界区时,其它线程如果也尝试获得同一个自旋锁,他们将会自旋等待该锁的释放,而不会阻塞。这意味着他们会反复检查锁是否可用,而不会被挂起,因此称为自旋。

自旋锁通常在临界区的代码尽可能保持短小和高效,以减少自旋等待的时间。如果临界区的代码过于复杂或执行时间过长,那么在高竞争情况下,自旋锁会导致线程不断自旋,浪费宝贵的 CPU 资源,因此要谨慎设计临界区的代码。

临界区的目标是确保在同一时间只有一个线程可以执行其中的代码,以保护共享资源免受并发访问的影响。自旋锁是一种用于实现这种同步的机制,它在一些情况下比传统的互斥锁(如 Mutex)更适用,尤其是在内核代码中和中断上下文中,因为它不会引发线程的阻塞。但是,自旋锁在高竞争情况下可能效率较低,因此在选择锁的类型时需要权衡不同的因素。

代码结构

上层

最上层的是通用自旋锁的代码(体系结构无关,平台无关),这一层的代码提供了两种接口:spinlock 接口和raw spinlock 接口。在没有配置PREEMPT_RT情况下,spinlock接口和raw spinlock接口一模一样,但是如果配置了PREEMPT_RT,spinlock接口走 rt spinlock,底层是基于rtmutex的。

"PREEMPT_RT" 是一种 Linux 内核的实时扩展,旨在提供更可预测和响应性能的内核。PREEMPT_RT 的全称是 "PREEMPT-Real Time",它通过对 Linux 内核的修改,使其更适合实时应用,以满足更严格的实时要求。

PREEMPT_RT 的主要特性包括:

  1. 抢占性内核(Kernel Preemption):PREEMPT_RT 引入了更多的内核抢占点,这意味着内核能够在更多的情况下响应实时任务的请求,而不会被普通内核任务阻塞。
  2. 减少中断禁用时间:PREEMPT_RT 通过减少中断禁用时间来改进内核响应性,这有助于减小实时任务受阻的机会。
  3. 更可预测的延迟:PREEMPT_RT 旨在减小任务切换和响应中断的时间,从而提供更可预测的性能,对于实时应用程序而言非常重要。
  4. 更好的时间管理:PREEMPT_RT 提供了更准确的时间管理机制,允许实时应用程序更精确地控制和协调时间敏感任务。
  5. 支持硬实时和软实时需求:PREEMPT_RT 可以根据应用程序的需求配置,以适应硬实时或软实时的要求。

这个扩展使 Linux 内核能够更好地胜任实时应用,如工业自动化、机器人控制、音视频处理等领域,其中时间敏感性和可预测性至关重要。

也就是说,这时候的spinlock不再禁止抢占,不在自旋等待,而是使用了支持 PI的睡眠锁来实现,因此有了更好的实时性。

"PI" 指的是 "Priority Inheritance"(优先级继承)。优先级继承是一种实时系统中用于解决资源竞争和优先级反转问题的技术。在实时系统中,任务通常有不同的优先级,而共享资源(如锁)的争用可能导致优先级反转问题,即低优先级任务持有了高优先级任务所需的资源,从而导致高优先级任务无法继续执行。

为了解决这个问题,引入了优先级继承机制,其中:

  1. 当一个高优先级任务等待一个由低优先级任务持有的资源时,低优先级任务的优先级会被提升到高优先级任务的优先级。这样,资源持有者的优先级被临时提高,以确保高优先级任务能够及时获得资源。
  2. 一旦高优先级任务获得了资源,低优先级任务的优先级会恢复到原来的状态。

这种优先级继承机制有助于防止优先级反转问题,确保高优先级任务能够按时执行。在实时系统中,特别是在 PREEMPT_RT 扩展的 Linux 内核中,使用支持优先级继承的睡眠锁来实现,可以提高实时性和可预测性,以确保实时任务能够按时响应。

而raw spinlock接口即便在配置了PREEMPT_RT下仍然保持传统自旋锁特性。

中间层

中间一层是区分SMP和UP的,在SMP和UP上,自旋锁的实现是不一样的。对于UP,自旋没有意义,因此spinlock的上锁和放锁操作退化为preempt disable(抢占禁用)和 enable(抢占启用)。而不是进行无效的自旋操作。这样可以确保 UP 系统中的任务不会浪费时间在自旋上,而是能够有效地等待锁的释放。

在单 CPU 系统中,通常可以使用更简单的同步机制,如互斥锁或信号量,来确保任务之间的互斥和同步。这些同步机制会在任务需要访问共享资源时将任务置于休眠状态,等待资源可用,而不是在一个循环中自旋等待资源的释放。

SMP平台上,除了抢占操作之外还有正常自旋锁的逻辑,具体如何实现自旋锁逻辑是和底层的CPU architecture相关的,后面我们会详细描述。

下层

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

自旋锁的演进

TAS

最早的自旋锁是TAS (test and set) 自旋锁,即通过原子指令来修改自旋锁的状态(locked、unlocked)。这种锁存在不公平的现象,具体原因如下:

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

为什么不同的cluster拓扑距离更近的cpu有更高概率抢到自旋锁

在多核系统中,不同的CPU核心可以分布在不同的物理或逻辑集群中,而每个集群可能具有不同的内部连接拓扑结构。集群内的核心通常会更容易快速访问彼此之间的共享资源(如内存),因此在争夺自旋锁时,拓扑距离更近的核心更有可能抢到锁。

这是因为集群内的核心通常会通过更快速的内部总线或互连结构进行通信,从而更容易快速获取锁和访问共享资源。与集群内的核心相比,与其他集群的核心进行通信可能需要更多的时间和额外的延迟。

在多核系统中,CPU核心之间的争夺自旋锁通常涉及到在多个核心之间共享数据结构,如锁本身或被锁保护的共享资源。因此,抢夺锁可能需要访问共享数据结构,而这个过程可能会受到拓扑距离的影响。

拓扑距离更近的核心更容易访问共享资源,因此在自旋等待期间,它们更有可能更快地获取锁。这导致了拓扑距离更近的核心在争夺锁时有更高的成功率。

这就是为什么在考虑锁竞争的情况下,多核系统的拓扑结构和拓扑距离通常被纳入考虑,以帮助最大程度地减少锁争用和提高性能。在某些情况下,可以通过合理地调度任务和考虑拓扑结构来降低锁竞争,从而提高多核系统的效率。

tiket based

为了解决这个问题,内核工程师又开发了ticket base的自旋锁,但是这种自旋锁在持锁失败的时候会对自旋锁状态数据next成员进行++操作。

qspinlock

当CPU数据巨大并竞争激烈的时候,自旋锁状态数据对应的cacheline会在不同cpu上跳来跳去,从而对性能产生影响,为了解决这个问题,qspinlock产生了。

什么是cacheline?

"cacheline" 是指缓存行,是计算机系统中用于缓存数据的最小单位。缓存行是一块固定大小的内存块,通常包含多个字节或字的数据。当 CPU 从主内存中加载数据时,它通常会将数据存储在缓存行中,以便更快地访问数据。

多个 CPU 核心可以共享相同的物理内存,但每个 CPU 核心通常都有自己的缓存。这意味着当多个 CPU 核心同时访问相同的数据时,数据可能会被存储在不同的 CPU 缓存中的不同缓存行上。这种情况下,不同 CPU 核心之间可能需要协调缓存行的数据一致性,以确保数据的正确性。

在多线程编程中,当多个线程同时访问共享数据时,可能会引发缓存一致性问题。这是因为一个线程在一个 CPU 核心上修改了共享数据的缓存行,但其他线程在不同 CPU 核心上可能仍然使用旧的缓存数据。为了解决这个问题,需要使用内存栅栏或原子操作来确保数据的一致性。

因此,在多核 CPU 系统中,缓存行的管理和缓存一致性是性能优化和多线程编程中需要考虑的重要因素。qspinlock 的设计考虑了缓存一致性的问题,以减少锁状态数据的频繁访问和缓存争用,从而提高性能。

具体qspinlock是如何减少内存访问的,请看下回分解。

参考连接

一文带你自旋锁探秘 - 知乎 (zhihu.com)

标签:RT,缓存,优先级,PREEMPT,自旋,探秘,CPU
From: https://www.cnblogs.com/lixiaomeng/p/17770942.html

相关文章

  • 探秘Java语言中子类调用父类的构造方法的方式
    父类的构造方法不能被子类继承。假定Base父类有以下构造方法:publicBase(Srtingmsg){this.msg=msg;}以下Sub类继承了Base类:publicclassSubextendsBase{}以上Sub类有一个隐含的默认构造方法,形式如下:publicSub(){}尽管在Base父类中定义了如下形式的构造方法:publicBase(Str......
  • [完结16章]React18内核探秘:手写React高质量源码迈向高阶开发
    点击下载——[完结16章]React18内核探秘:手写React高质量源码迈向高阶开发  提取码:8epr手写React高质量源码,迈向高阶开发React18内核探秘:手写React高质量源码迈向高阶开发batching批处理,说的是,可以将回调函数中多个setState事件合并为一次渲染,因此是异步的。解决的问题是......
  • 使用 C++11 原子类型 `std::atomic_flag` 实现的自旋锁
    使用C++11原子类型std::atomic_flag实现的自旋锁:#include<atomic>classSpinlock{public:Spinlock():flag(ATOMIC_FLAG_INIT){}voidlock(){while(flag.test_and_set(std::memory_order_acquire));}voidunlock(){flag.cl......
  • Go指针探秘:深入理解内存与安全性
    Go指针为程序员提供了对内存的深入管理能力,同时确保了代码的安全性。本文深入探讨了Go指针的基础概念、操作、深层理解及其特性与限制。通过深入了解其设计哲学和应用,我们可以更好地利用Go的强大功能。关注公众号【TechLeadCloud】,分享互联网架构、云服务技术的全维度知识。作......
  • 探秘移动端BI:发展历程与应用前景解析
    什么是移动端BI维基百科上对于移动端商业智能的定义是这样的>MobileBIisasystemthatpresentshistoricalandreal-timeinformationonmobiledevicesforeffectivedecision-makingandmanagementsupport.Itenablesanalysisonsmartphonesandtablets,lead......
  • linux --- 自旋锁(spinlock_t)
    定义自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于......
  • 如何使用C++11原子操作实现自旋锁
    什么是自旋锁?C++自旋锁是一种低层次的同步原语,用于保护共享资源的访问。自旋锁是一种轻量级的锁,适用于短时间的资源锁定。自旋锁的特点:当一个线程尝试获取已经被另一个线程占有的自旋锁时,这个线程会进入一个循环(自旋),在这个循环中它不断地检查锁是否已经被释放。如果锁已经被释放,那......
  • 智能化医疗护航:探秘智慧医疗电子处方系统源码
    时下,智慧医疗电子处方系统作为智能医疗的重要组成部分,正以其高效、精准的特性,为患者和医生带来全新的医疗体验。本文将深入探讨智慧医疗电子处方系统的源码,揭示其背后的技术原理和创新之处。一、引言传统医疗领域一直面临着繁琐的纸质处方、处方传递不便等问题。智慧医疗电子处方系......
  • 构建高性能后端:探秘Nginx与Elasticsearch的技术协同
    在如今的信息时代,高性能的后端技术对于应用的成功至关重要。本文将深入探讨两个关键技术领域:Nginx反向代理和Elasticsearch全文搜索。通过详细的原理解析和实际代码示例,揭示它们如何协同工作,为应用的性能和效率提供强大支持。Nginx反向代理:背后的原理Nginx不仅是一款优秀的Web服务......
  • Python高级技巧之元编程与元类探秘
    在Python的后端开发中,元编程和元类是高级技巧,它们使得你可以在运行时创建、操作和修改代码结构。本文将深入探讨Python中的元编程和元类,揭示它们的奥秘,帮助你更好地理解和运用这些强大的技术。元编程的概念和用途元编程是一种编程范式,它涉及编写能够操作和生成其他代码的代码。元编......