linux驱动中的互斥途径一二:中断屏蔽和原子操作

linux驱动 专栏收录该内容
41 篇文章 4 订阅

1. 中断屏蔽:

1.1 说明:

在单 CPU 范围内避免竞态的简单而省事的方法是在进入临界区之前屏蔽系统的中断
  • 优点是:当中断屏蔽的时候,内核抢占进程之间的并发也得以避免了
  • 缺点是:由于linux的异步I/O、进程调度等很多重要操作都依赖于中断,这些功能在中断屏蔽期间将不能使用。当长时间的屏蔽中断,有可能导致数据的丢失甚至系统的崩溃。

    1.2 使用

    local_irq_disable()
    local_irq_enable()
    两者配合 只能禁止和使能本 CPU 内的中断,这就是说,在解决 SMP 多 CPU 引起的竞态的情况是无能为力的,在这种情况下适宜与自旋锁联合使用。

    local_irq_save(flag)
    local_irq_restore(flag)
    禁止中断,保存目前的 CPU 的中断位信息

    local_bh_disable()
    locla_bh_enable()
    只是禁止中断的底半部

    2. 原子操作:

    原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
    或者 “可被中断的一个或一系列操作”
    原子操作分为两类:整型原子操作、位原子操作

    2.1 整型原子操作:

    设置原子变量的值
    void atomic_set(atomic_t *v, int i); /* 设置原子变量的值为 i */
    atomic_t v = ATOMIC_INIT(0); /* 定义原子变量 v ,初始化为0 */
    获取原子变量的值
    atomic_read(atomic_t *v); /* 返回原子变量的值 */
    加/减
    void atomic_add(int i, atomic_t *v); /* 原子变量增加i */
    void atomic_sub(int i, atomic_t *v); /* 原子变量减少i */
    自增/自减
    void atomic_inc(atomic_t *v); /* 自加1 */
    void atomic_dec(atomic_t *v); /* 自减1 */
    操作并测试
    int atomic_inc_and_test(atomic_t *v);
    int atomic_dec_and_test(atomic_t *v);
    int atomic_sub_and_test(int i, atomic_t *v);
    对原子变量执行自增、自减和减操作后(无加)测试其是否为 0,
    0,true
    !0,false
    操作并返回
    int atomic_add_return(int i, atomic_t *v);
    int atomic_sub_return(int i, atomic_t *v);
    int atomic_inc_return(atomic_t *v);
    int atomic_dec_return(atomic_t *v);
    执行完操作后,返回新的值

    2.2 位原子操作:

    置位: -- 置1
    void set_bit(nr, void *addr);
    功能:
    将 addr 地址的第 nr 位置为 1
    清零
    void clear_bit(nr, void *addr);
    位翻转
    void change_bit(nr, void *addr);
    测试
    test_bit(nr, void *addr);
    功能:
    返回 addr 位的第 nr 位
    测试并操作
    int test_and_set_bit(nr, void *addr);
    int test_and_clear_bit(nr, void *addr);
    int test_and_change_bit(nr, void *addr);
    功能:
    相当于先执行了test_bit(nr, void *addr)后再执行 xxx_bit(nr, void *addr)

    3. 原子操作的实例:

    实现 设备最多只能被一个进程打开:

    关键的函数:

    atomic_t v = ATOMIC_INIT(1);
    
    static int hello_open (struct inode *inode, struct file *file)
    {
        if (!atomic_dec_and_test(&v))
        {
            atomic_inc(&v);
            return -EBUSY;
        }
        printk (KERN_INFO "Hey! device opened\n");
    
        return 0;
    }
    
    static int hello_release (struct inode *inode, struct file *file)
    {
        atomic_inc(&v); 
        printk (KERN_INFO "Hmmm! device closed\n");
    
        return 0;
    }

    函数说明:(hello_open函数)
    ①第一次打开设备驱动的时候 v = 1,v - 1 = 0 ,atomic_dec_and_test(&v) 结果是 true,不进循环,不返回EBUSY,执行下边内容。
    ②第二次打开设备驱动,v = 0, v - 1 = -1,atomic_dec_and_test(&v) 结果是 false,进循环,直接返回。

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值