• linux并发控制之原子操作


    原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
    分为两类:整型原子操作 和 位原子操作。
    特点:
    1.任何情况下操作都是原子的。
    2.都依赖底层的CPU的原子操作来实现,所以和CPU架构密切相关。

    注意:
        1.原子操作在不同体系架构实现的方法不同,基本采用汇编实现
        2.上述的整数原子函数集仅针对32位,内核中关于64位有另一套函数
        3.对于SMP系统,内核还提供了local_t数据类型,实现对单个CPU的整数原子操作,接口函数仅将atomic_替换成local_即可,定义于linux/asm-generic/local.h

    一.整型原子操作
    定义于#include<asm/atomic.h>
    分为 定义,获取,加减,测试,返回。

    void atomic_set(atomic_t *v,int i);    //设置原子变量v的值为i
    atomic_t v = ATOMIC_INIT(0);     //定义原子变量v,并初始化为0;

    atomic_read(atomic_t* v);     //返回原子变量v的值;

    void atomic_add(int i, atomic_t* v);     //原子变量v增加i;
    void atomic_sub(int i, atomic_t* v);    

    void atomic_inc(atomic_t* v);     //原子变量增加1;
    void atomic_dec(atomic_t* v);     

    int atomic_inc_and_test(atomic_t* v);        //先自增1,然后测试其值是否为0,若为0,则返回true,否则返回false;
    int atomic_dec_and_test(atomic_t* v);        
    int atomic_sub_and_test(int i, atomic_t* v);     //先减i,然后测试其值是否为0,若为0,则返回true,否则返回false;
    注意:只有自加,没有加操作

    int atomic_add_return(int i, atomic_t* v);   //v的值加i后返回新的值;
    int atomic_sub_return(int i, atomic_t* v);  
    int atomic_inc_return(atomic_t* v);     //v的值自增1后返回新的值;
    int atomic_dec_return(atomic_t* v);    

    二.位原子操作
    定义于#include<asm/bitops.h>
    分为 设置,清除,改变,测试

    void set_bit(int nr, volatile void* addr);        //设置地址addr的第nr位,所谓设置位,就是把位写为1;
    void clear_bit(int nr, volatile void* addr);      //清除地址addr的第nr位,所谓清除位,就是把位写为0;

    void change_bit(int nr, volatile void* addr);     //把地址addr的第nr位反转;

    int test_bit(int nr, volatile void* addr);    //返回地址addr的第nr位;

    int test_and_set_bit(int nr, volatile void* addr);    //测试并设置位;若addr的第nr位非0,则返回true; 若addr的第nr位为0,则返回false;
    int test_and_clear_bit(int nr, volatile void* addr);    //测试并清除位;
    int test_and_change_bit(int nr, volatile void* addr);    //测试并反转位;
    上述操作等同于先执行test_bit(nr,voidaddr)然后在执行xxx_bit(nr,voidaddr)

    举个简单例子:
    为了实现设备只能被一个进程打开,从而避免竞态的出现

    static atomic_t scull_available = ATOMIC_INIT(1);      //init atomic

    在scull_open 函数和scull_close函数中:

    int scull_open(struct inode *inode, struct file *filp)
    {
        struct scull_dev *dev;         // device information

        dev = container_of(inode->i_cdev, struct scull_dev, cdev);
        filp->private_data = dev;         // for other methods 
        if(!atomic_dec_and_test(&scull_available)){
            atomic_inc(&scull_available);
            return -EBUSY;
        }
        return 0;         // success 
    }

    int scull_release(struct inode *inode, struct file *filp)
    {
        atomic_inc(&scull_available);
        return 0;
    }

    同样也可以用位原子操作实现
  • 相关阅读:
    luogu P1144 最短路计数
    codevs 1006 等差数列
    luogu P2419 [USACO08JAN]牛大赛Cow Contest
    luogu cogs 选数
    luogu P1186玛丽卡
    leetcode[69]Sqrt(x)
    leetcode[70]Climbing Stairs
    leetcode[71]Simplify Path
    leetcode[72]Edit Distance
    leetcode[73]Set Matrix Zeroes
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6332964.html
Copyright © 2020-2023  润新知