• Linux驱动开发4——并发和竞态


    Linux系统处于一个高并发的运行环境,不管是系统调用还是中断都要求可重入,但是有一些系统资源处于临界区,因此,必须保证临界区资源访问的原子性。

    对于临界区资源被占用时,发起访问的进程,有三种处理方法——睡眠、阻塞以及撤销。

    Linux驱动编程中,通常不建议使用锁机制,因为容易导致死锁问题。不使用锁的场景,尽量使用kfifo缓冲队列来存取数据;在必须使用锁的场景,建议使用信号量和自旋锁。

    信号量通常用在可以睡眠的场景,如进程上下文;而自旋锁通常用在不可睡眠的场景,如中断上下文。

    1、信号量

    #include <linux/semaphore.h>
    
    信号量初始化
    void sema_init(struct semaphore *sem, int val);
    
    互斥信号量
    DECLARE_MUTEX(name);
    DECLARE_MUTEX_LOCKED(name);
    
    void init_MUTEX(struct semaphore *sem);
    void init_MUTEX_LOCKED(struct semaphore *sem);
    
    获取信号量
    void down(struct semaphore *sem);
    int down_interruptible(struct semaphore *sem); /* 可中断,即进入睡眠状态等待信号量,需要一直检查返回值并且针对性地响应 */
    int down_trylock(struct semaphore *sem); /* 从不睡眠,如果信号量被占用,立刻返回 */
    
    释放信号量
    void up(struct semaphore *sem);

     示例:

    if (down_interruptible(&sem))
        return -ERESTARTSYS;

    /* 临界区资源访问 */

    up(&sem);

    1.1、读写信号量

    由信号量衍生,可以允许多个用户并发读,一个用户互斥写。

    #include <linux/rwsem.h>
    
    /* 初始化 */
    void init_rwsem(struct rw_semaphore *sem);
    
    /* 读者接口 */
    void down_read(struct rw_semaphore *sem);
    void down_read_trylock(struct rw_semaphore *sem);
    void up_read(struct rw_semaphore *sem);
    
    /* 写者接口 */
    void down_write(struct rw_semaphore *sem);
    void down_write_trylock(struct rw_semaphore *sem);
    void up_write(struct rw_semaphore *sem);

    2、自旋锁

    #include <linux/spinlock.h>
    
    初始化
    spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
    或者
    void spin_lock_init(spinlock_t *lock);
    
    
    获取自旋锁
    void spin_lock(spinlock_t *lock);
    释放自旋锁
    void spin_unlock(spinlock_t *lock);

    获取自旋锁时保存中断状态,并禁止本地处理器中断,释放时打开中断
    void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
    void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);

    获取自旋锁时禁止中断,释放时打开中断
    void spin_lock_irq(spinlock_t *lock);
    void spin_unlock_irq(spinlock_t *lock);

    2.1、读写自旋锁

    类似于读写信号量,读写自旋锁是自旋锁的衍生。

    3、原子量(atomic)

    4、顺序锁(seqlock)

    顺序锁用来保护较小的资源,快速存取的场景。它允许读者释放对资源的存取,但是要求读者检查与写者的冲突,如果发生冲突,重试存取操作。

    seqlock通常不能用在保护包含指针的数据结构,因为读者可能跟随一个无效指针而写者在改变数据结构。

    #include <linux/seqlock.h>
    
    seqlock_init(seqlock_t *lock);

    5、读取-拷贝-更新(RCU)

    一种高级的互斥方法

  • 相关阅读:
    引导用户关注公众号
    python计算两组数据的P值
    【style-resources-loader】自动化导入CSS
    【concurrently】前端工程化并行解决方案
    【已解决】K8s + Ingress + Nodejs代理服务报错:413 Request Entity Too Large
    Python定时任务框架APScheduler实战Demo
    前端团队codeReview规范以及流程
    Git使用关键理解
    Vue+ESLint+Git钩子函数pre-commit配置教程
    【MongoDB】查询字段对应的数组中包含某个值
  • 原文地址:https://www.cnblogs.com/justin-y-lin/p/10689472.html
Copyright © 2020-2023  润新知