淘宝客 网站 建站在线查询企业

当前位置: 首页 > news >正文

淘宝客 网站 建站,在线查询企业,seo3分子的立体构型,网站实施要求一、spin_lock概述 Spinlock是linux内核中常用的一种互斥锁机制#xff0c;和mutex不同#xff0c;当无法持锁进入临界区的时候#xff0c;当前执行线索不会阻塞#xff0c;而是不断的自旋等待该锁释放。正因为如此#xff0c;自旋锁也是可以用在中断上下文的。也正是因为…一、spin_lock概述 Spinlock是linux内核中常用的一种互斥锁机制和mutex不同当无法持锁进入临界区的时候当前执行线索不会阻塞而是不断的自旋等待该锁释放。正因为如此自旋锁也是可以用在中断上下文的。也正是因为自旋临界区的代码要求尽量的精简否则在高竞争场景下会浪费宝贵的CPU资源。

  1. spin lock 的发展 (1) TAS和CAS 硬件对同步的支持-TAS和CAS指令 - 元思 - 博客园 锁只有一个原子变量通过原子指令来修改自旋锁的状态locked、unlocked。问题是没有公平可言无法让等待最长的那个任务优先拿到锁为了解决这个问题引入了ticket spinlock。 如果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 spinlockMCS 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具有很好的可扩展性也就是无论当前锁的争抢程度如何性能都可以得到保证。 Linux内核同步原语之自旋锁Spin Lock_mcs自旋锁-CSDN博客
  2. spin lock 的命令规范 1spinlock对于没有打上Linux-RT实时Linux的patch的系统spin_lock只是简单地调用raw_spin_lock实际上他们是完全一样的如果打上这个patch之后spin_lock会使用信号量完成临界区的保护工作带来的好处是同一个CPU可以有多个临界区同时工作而原有的体系因为禁止抢占的原因一旦进入临界区其他临界区就无法运行新的体系在允许使用同一个临界区的其他进程进行休眠等待而不是强占着CPU进行自旋操作。 2raw_spinlock即便是配置了PREEMPT_RT也要顽强的spin 3arch_spinlockspin lock是和architecture相关的arch_spinlock是architecture相关的实现 对于UP平台所有的arch_spinlock_t都是一样的定义如下 typedef struct { } arch_spinlock_t; 什么都没有一切都是空啊。当然这也符合前面的分析对于UP即便是打开的preempt选项所谓的spin lock也不过就是disable preempt而已不需定义什么spin lock的变量。 对于SMP平台这和arch相关我们在下一节描述。 3. spin lock 特点 自旋锁在实现的时候调用preempt_disable关闭了内核抢占。也就是说运行在一个CPU的代码使用spin_lock加锁之后基于该CPU的内核抢占就被禁止了。因此会产生以下影响 在单核系统只需要禁止内核抢占等同于关闭了进程切换从而就不存在进程同步的问题。由于禁止了内核抢占如果进程获取自旋锁之后在临界区中睡眠将会导致其他进程都无法获取CPU而运行从而不能唤醒睡眠的自旋锁因此禁止在自旋锁中使用睡眠等函数除了中断但是中断通常不会唤醒睡眠的自旋锁在多核系统虽然禁止了当前CPU内核抢占但是如果存在多个CPU仍然存在多个CPU对自旋锁共享变量同时访问的问题因此在多核系统除了关闭CPU内核抢占、还需要通过独占指令ldrex、strex实现共享变量的互斥访问 自旋锁的特点有 spinlock是一种死等的锁机制semaphore可以允许多个执行单元进入spinlock不行一次只能有一个执行单元获取锁并进入临界区其他的执行单元都是在门口不停的死等执行时间短由于spinlock死等这种特性如果临界区执行时间太长那么不断的在临界区门口“死等”的那些执行单元会浪费CPU由于在中断上下文中是不允许睡眠的因此spinlock可以在中断上下文中适用而信号量和互斥锁都会导致睡眠无法在中断上下文中使用 思考 Linux内核之禁止中断和禁止内核抢占_禁止中断,禁止内核抢占-CSDN博客  真正的上锁前为何要调用preempt_disable()来关闭抢占的case_preemption disabled-CSDN博客  二、代码结构 最上层是通用自旋锁代码体系结构无关平台无关这一层的代码提供了两种接口spinlock接口和raw spinlock接口。在没有配置PREEMPT_RT情况下spinlock接口和raw spinlock接口是一毛一样的。如果配置了PREEMPT_RTspinlock接口走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.htypedef 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.hstatic __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, _RETIP);//检查锁的有效性一般是空操作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); } spin_acquire #define spin_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) #define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i) lockdep.c - kernel/locking/lockdep.c - Linux source code v5.4.90 - Bootlin Elixir Cross Referencer /** We are not always called with irqs disabled - do that here, and also avoid lockdep recursion:*/ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,int trylock, int read, int check,struct lockdep_map *nest_lock, unsigned long ip) {unsigned long flags;if (unlikely(current-lockdep_recursion))return;raw_local_irq_save(flags);check_flags(flags);current-lockdep_recursion 1;trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);lock_acquire(lock, subclass, trylock, read, check,irqs_disabled_flags(flags), nest_lock, ip, 0, 0);current-lockdep_recursion 0;raw_local_irq_restore(flags); } raw_local_irq_save 宏禁用硬件中断因为自旋锁可能被硬件中断所获取。以这样的方式获取的话程序将不会被抢占。 raw_local_irq_restore 宏再次启动硬件中断。 主要工作将在 __lock_acquire 函数中定义这个函数在lockdep.c - kernel/locking/lockdep.c - Linux source code v5.4.90 - Bootlin Elixir Cross Referencer 源代码文件中。 __lock_acquire 函数看起来很大。我们将试图去理解这个函数要做什么但不是在这一部分。事实上这个函数于 Linux内核锁验证器 (lock validator) 密切相关暂时先跳过分析。 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(); } 同步原语 - 自旋锁简介 - 《Linux 内核揭秘中文版》 - 书栈网 · BookStack 自旋锁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博客 linux同步机制-自旋锁 - 大奥特曼打小怪兽 - 博客园  spinlock.h - include/linux/spinlock.h - Linux source code v5.4.90 - Bootlin Elixir Cross Referencer