Linux内核同步

解决的问题:
      进程A和进程B同时对 XXX(共享资源)进行操作,会产生竞争行为

解决方法:
      保证对共享资源的互斥访问(一个执行单元在访问共享资源的时候,其他的执行单元被禁止访问)
      访问共享资源的代码区块叫做“临界区”,临界区需要以某种互斥机制加以保护:自旋锁、信号量(进程)

linux内核中可能引起互斥访问的情形:
1.进程和进程之间                     解决方式:信号量
2.进程和其它内核代码             解决方式:自旋锁
3.进程和中断代码                    解决方式:自旋锁

信号量:
    Linux中的信号量是一种睡眠锁。假如进程A先持有信号量F,然后进程B试图获得已经被进程A持有的信号量F时,信号量会将进程B推入等待队列,然后让其睡眠。当持有信号量的进程A将信号量F释放后,进程B才会被被唤醒,从而获得这个信号量,继续执行进程B的代码

信号量基本使用形式为:

定义信号量
    struct semaphore sem;
初始化信号量
    void sema_init(struct semaphore * sem, int val);
初始化互斥信号量
  void init_MUTEX(struct semaphore *sem);
  等同于:sema_init(struct semaphore *sem, 1);
获得信号量
    void down(struct semaphore *sem);
    此函数用于获得信号量sem,它会导致睡眠,因而不能用于中断上下文
    int down_interruptible(struct semaphore *sem);
    同down(),不同之处在于,因为down()而进入睡眠状态的进程不能被信
    号打断,而因为down_interruptible()而进入睡眠状态的进程能被信号
    打断,信号也会导致该函数返回,这时该函数返回值非0
    int down_trylock(struct semaphore *sem);
    该函数尝试获得信号量sem,如果能够立即获得,它就获得该信号量返回
    0,否则,返回非0值,它不会导致调用者睡眠,可以在中断上下文使用
释放信号量
    void up(struct semaphore *sem)
    该函数释放信号量sem,唤醒等待者

信号量使用注意:
1.可以长期加锁
2.只能用于进程上下文,不能用于中断上下文
3.在持有自旋锁的同时,不能持有信号量

自旋锁:

    自旋锁最多只能被一个内核任务持有。如果一个内核任务试图请求一个已经被别的内核任务持有的自旋锁,那么CPU就会一直进行忙循环等待锁重新可用。
    在linux kernel的实现中,经常会遇到这样的场景:共享数据被中断上下文和进程上下文访问,该如何保护呢?如果只有进程上下文的访问,那么可以考虑使用semaphore或者mutex的锁机制,但是现在中断上下文也参和进来,那些可以导致睡眠的lock就不能使用了,这时候,可以考虑使用spin lock。因为中断上下文不允许睡眠。

自旋锁使用方法:

spin_lock(&mr_lock);//加锁

。。。。。//临界区代码

spin_unlock(&mr_lock);//解锁

初始化自旋锁:

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);

        获得自选锁之前禁止本地cpu中断,之前的中断状态保存在flags里

       void spin_lock_irq(spinlock_t *lock);

       获得自选锁之前禁止本地cpu中断,但不保存中断状态

       void spin_lock_bh(spinlock_t *lock);

       获得自选锁之前禁止软中断,允许硬件中断

相应的释放函数

void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);

void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);

自旋锁使用注意:
     1.不可以长期加锁,短期加锁
     2.会有系统开销(cpu忙转),不可滥用
     3.在持有自旋锁的同时,不能持有信号量
     4.在持有自旋锁的同时,不能再二次持有它(死锁)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值