Linux spin_lock如何实现——依赖关中断和关抢占

本文深入探讨Linux内核中的spin_lock,阐述其在多核和抢占环境下的应用,包括spin_lock_irqsave等变体的用途,以及为何在关中断后还需要禁止抢占以防止死锁。文章通过不同场景的加锁策略,解析spin_lock在处理并发和中断问题中的关键作用。
摘要由CSDN通过智能技术生成

一、自旋锁用来干什么

If you have understood Mutex then Spinlock is also similar. Both are used to protect a shared resource from being modified by two or more processes simultaneously.

二、Linux kernel中spinlock的需求场景

If the kernel is running on a uniprocessor and CONFIG_SMP, CONFIG_PREEMPT aren’t enabled while compiling the kernel then spinlock will not be available. Because there is no reason to have a lock when no one else can run at the same time.

But if you have disabled CONFIG_SMP and enabled  CONFIG_PREEMPT then spinlock will simply disable preemption, which is sufficient to prevent any races.

也就是说,spinlock只适用于开多核和开调度器抢占的情况。这里就引出自旋锁互斥的三个要点:

1. 自旋锁互斥包括:多核并发互斥 + 单核中断互斥 + 单核抢占互斥;
2. 获取自旋锁之前关中断,目的就是为了避免单核上中断导致的竞争条件;
3. 获取自旋锁之前关抢占,目的就是为了避免单核上抢占导致的竞争条件;

三、自旋锁本尊以及自旋锁的多种变形
(1)、本尊
    spin_lock(lock);        /* 死等一个原子变量值有效,其本身是可以被中断打断以及被进程调度抢占的 */
(2)、多种变形
    #define spin_lock_irqsave(lock, flags)        do { local_irq_save(flags);       spin_lock(lock); } while (0)    
    #define spin_lock_irq(lock)            do { local_irq_disable();         spin_lock(lock); } while (0)
    #define spin_lock_bh(lock)            do { local_bh_disable();          spin_lock(lock); } while (0)

    #define read_lock_irqsave(lock, flags)        do { local_irq_save(flags);       read_lock(lock); } while (0)
    #define read_lock_irq(lock)            do { local_irq_disable();         read_lock(lock); } while (0)
    #define read_lock_bh(lock)            do { local_bh_disable();          read_lock(lock); } while (0)

    #define write_lock_irqsave(lock, flags)        do { local_irq_save(flags);      write_lock(lock); } while (0)
    #define write_lock_irq(lock)            do { local_irq_disable();        write_lock(lock); } while (0)
    #define write_lock_bh(lock)            do { local_bh_disable();         write_lock(lock); } while (0)

    #define spin_unlock_irqrestore(lock, flags)    do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
    #define spin_unlock_irq(lock)            do { spin_unlock(lock);  local_irq_enable();       } while (0)
    #define spin_unlock_bh(lock)            do { spin_unlock(lock);  local_bh_enable();        } while (0)

    #define read_unlock_irqrestore(lock, flags)    do { read_unlock(lock);  local_irq_restore(flags); } while (0)
    #define read_unlock_irq(lock)            do { read_unlock(lock);  local_irq_enable();       } while (0)
    #define read_unlock_bh(lock)            do { read_unlock(lock);  local_bh_enable();        } while (0)

    #define write_unlock_irqrestore(lock, flags)    do { write_unlock(lock); local_irq_restore(flags); } while (0)
    #define write_unlock_irq(lock)            do { write_unlock(lock); local_irq_enable();       } while (0)
    #define write_unlock_bh(lock)            do { write_unlock(lock); local_bh_enable();        } while (0)
(3)、local_irq_save与local_irq_disable的区别?
    local_irq_save是既关闭中断,也保留CPU状态寄存器,以用于恢复之前状态
    local_irq_disable只关闭状态,不保留CPU状态寄存器,之后不会恢复之前的CPU状态

四、问题:spin_lock_irqsave关中断后,为什么要再禁止抢占呢,不多余吗?
    static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
    {
            unsigned long flags;


            local_irq_save(flags);                            /* 第一步:关硬中断 */
            preempt_disable();                                /* 第二步:关抢占 */
            spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);    /* 第三步:获取lock */
            ......

     }

如果不禁止内核抢占,可能会有以下的情况发生(假设进程B比进程A具有更高的优先级):
    a. 进程A获得spinlock lock
    b. 进程B运行(抢占进程A)
    c. 进程B获取spinlock lock
由于进程B比进程A优先级高,所以进程B在进程A之前运行,而进程B需要进程A释放lock之后才能运行,于是,死锁。

所以,禁止中断并不能完全禁止抢占。


五、spinlock应用场景和案例

1.Approach 1 (Locking between User context) ——If you share data with user context (between Kernel Threads), then you can use this approach.

加锁: spin_lock(spinlock_t *lock) ——This will take the lock if it is free, otherwise, it’ll spin until that lock is free (Keep trying).

尝试加锁:spin_trylock(spinlock_t *lock) —— Locks the spinlock if it is not already loc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

denglin12315

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值