LINUX内核中并发与竟态的解决方法

一,linux内核中并发和竟态的解决方法

    >竟态是怎么产生的?产生的根本原因是什么?
    
        首先我们知道,在多个应用程序通过设备文件同时访问一个硬件资源的时候,
    竟态就会产生了.
        而产生竟态的根本原因就是(并发)总结归为三点↓
        1> 在一个单核处理器上,内核支持抢占.
        2> 在多核处理器上,内核与内核之间会产生竟态.
        3> 中断和进程间会产生竟态(指的是支持嵌套的中断)
        
    
二,解决竟态的方法,
    首先我们知道,产生竟态的原因是并发,所以我们只需要考虑让其变成互斥就可以解决这个问题.
所以在内核中我们可以让进程间实现互斥的办法有:中断屏蔽,自旋锁,信号量,互斥体,原子变量/操作.
这些解决竟态的方法有利有弊,各有所长.
    1>中断屏蔽
    
        特点:针对单核的cpu有效,中断屏蔽就是关闭中断.中断屏蔽保护的临界区很小,里面不可以有
    延时或者耗时的操作(copy_to_user)如果中断屏蔽的时间很长,会导致用户的数据丢失或内核的崩溃.
    
    API:
            iocal_irq_disable();
            //需要受到保护的临界区
            iocal_irq_enable();
        
        因为在开发的工作学习的过程中,我们接触单核处理器的可能性就没有,所以说这个中断屏蔽可能也不会用到.
        
    2>自旋锁
        
        特点:当一个进程获取到自旋锁后,另一个进程也想获取这把锁,此时后一个进程就处于一个自旋状态(消耗cpu资源)
    自旋锁是针对于多核处理器设计的,自旋锁是一个忙等锁,自旋的状态会消耗cpu的咨询的资源,并且会导致死锁,自旋锁
    保护的临界区要尽可能的短,里面不能有延时,耗时,休眠等操作,包括copy_from/to_user的操作,自旋锁在上锁的时候会
    关闭抢占.
    
    API:
        
        1,spinlock_t lock;//定义一个自旋锁(全局)
        
        2,spin_lock_init(&lock);//初始化一个自旋锁(初始化操作,毋庸置疑放在入口函数里)
        
        3,spin_lock(&lock); //上锁操作
        (中间是临界区,切记一定是很小的.所以我们通常来定义一个变量)
        4,spin_unlock(&lock); //解锁操作
        
    3>信号量
    
        特点:当一个进程获取到信号量之后,另一个进程也想获取这个信号量,此时后一个进程处于一个休眠的状态.
    信号量不会产生死锁,并且保护的临界区可以很大,里面可以有延时,耗时,甚至休眠的操作,信号量在等待获取锁的
    过程是不消耗cpu资源的,信号量不会关闭抢占.由于自旋锁在使用的时候,要求临界区不能做休眠操作,但是在某些
    场合需要在临界区做休眠操作,又要考虑竟态问题,此时可以使用信号量来保护临界区。
    
    API:
        

          struct semaphore sem;//定义一个信号量
        
           void sema_init(struct semaphore *sem, int val)//初始化
           当val初始化为1的时候,才具备互斥的效果。
           当val初始化为0的时候,就是同步机制。
           
        
          void down(struct semaphore *sem); //上锁操作
          int  down_trylock(struct semaphore *sem);//上锁操作 
            二选一即可(函数尝试获取信号量sem,成功或不成功获取信号量,
            函数都将立即返回,而down()函数在不能成功获取时将进入睡眠状态而一直等待下去)
            成功返回0,失败返回1,不会休眠
    
          void up(struct semaphore *sem); //解锁操作
    
    
    
    
    4 >互斥体
            互斥体:当一个进程获取到互斥体之后,另外一个进程
    也想获取这个互斥体,此时后一个进程处于休眠状态。互斥体不会产生死锁,
    保护的临界区可以很大,里面可以有延时,耗时,甚至休眠的操作。互斥体在等待获取锁的过程是不消耗cpu资源
    互斥体不会关闭抢占。在保护临界区较少的临界资源时,互斥体的效率高于信号量。
        
        API:
            
              struct mutex mutex;//定义锁
            
               mutex_init(&mutex);//初始化锁    
               
            
              mutex_lock(struct mutex *lock);//上锁
              int  mutex_trylock(struct mutex *lock)
              成功返回1,失败返回0,不会休眠
            
             void  mutex_unlock(struct mutex *lock)//解锁
    
    
    5>原子操作    
            typedef struct {
                int counter;
            } atomic_t;
            原子操作本身就是一个变量,这个变量的修改内核做了
            防竞态的过程,对这个变量值修改的过程是通过内联汇编
            完成。意思就是对这个变量的操作看成一个不可被分割的
            整体。

            atomic_t atm=ATOMIC_INIT(-1);
            atomic_inc_and_test(atomic_t *v)
            加1后和0比较,如果结果为0,表示获取锁成功了,
            获取锁成功返回真
            atomic_dec(atomic_t *v)
                |                 |    
                |                |
                      ↑
                    二选一
                      ↓
                |               |
                |               |    
            atomic_t atm=ATOMIC_INIT(1);
            atomic_dec_and_test(atomic_t *v)
            减1后和0比较,如果结果为0,表示获取锁成功了,
            获取锁成功返回真
            atomic_inc(atomic_t *v)

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值