zoukankan      html  css  js  c++  java
  • linux并发concurrency控制

    解决竞态(race conditions)最根本的途径是对共享资源的互斥访问,访问共享资源的代码区被称为临界区(critical sections),对临界区的代码需要以某种互斥机制加以保护。
    常见的互斥机制有:中断屏蔽、原子操作、自旋锁、信号量、互斥体。

    1. 中断屏蔽
    由于linux内核的进程调度和异步IO等操作都是依赖中断来实现的,所以中断屏蔽也可以避免内核强占进程之间的竞态发生。
    定义在linux/irqflags.h,实现在asm/irqflags.h中。
    local_irq_disable();
    local_irq_enable();

    local_irq_save(flags);
    local_irq_restore(flags);

    local_bh_disable();
    local_bh_enable();

    2. 原子操作
    原子操作分类:整型原子操作和位原子操作
    整型原子操作
    asm/atomic.h
    void atomic_set(atomic_t *v, int i);
    atomic_t v = ATOMIC_INIT(0);
    atomic_read(atomic_t *v);
    void atomic_add(int i, atomic_t *v);
    void atomic_sub(int i, atomic_t *v);
    void atomic_inc(atomic_t *v);
    void atomic_dec(atomic_t *v);
    int atomic_inc_and_test(atomic_t *v);
    int atomic_dec_and_test(atomic_t *v);
    int atomic_sub_and_test(atomic_t *v);
    操作后测试是否为0,为0返回true,否则返回false。
    int atomic_add_return(int i, atomic_t *v);
    操作后返回新值。

    位原子操作
    asm/bitops.h
    void set_bit(nr, void *addr);
    void clear_bit(nr, void *addr);
    void change_bie(nr, void *addr);
    test_bit(nr, void *addr);
    int test_and_set_bit(nr, void *addr);
    int test_and_clear_bit(nr, void *addr);
    int test_and_change_bit(nr, void *addr);

    3. 自旋锁
    1)自旋锁主要针对SMP或单CPU且内核可强占的情况,对于单CPU且内核不可强占的系统自旋锁退化为空操作。
    2)在单CPU且内核可强占的系统中,自旋锁持有期间内核的强占被禁止。

    使用注意:
    1)不能递归持有自旋锁。
    2)持有自旋锁后不能阻塞。

    linux/spinlock_types.h
    spinlock_t lock;
    spin_lock_init(&lock);
    spin_lock(&lock);
    spin_trylock(&lock);
    spin_unlock(&lock);

    spin_lock_irq();
    spin_unlock_irq();
    spin_lock_irqsave();
    spin_unlock_irqrestore();
    spin_lock_bh();
    spin_unlock_bh();

    读写自旋锁
    写操作时最多只能有一个写进程。
    顺序锁

    4. 信号量
    linux/semaphore.h,实现在ipc/sem.c和kernel/semaphore.c中。
    struct semaphore sem;
    void sema_init(struct semaphore *sem, int val);
    void down(struct semaphore *sem);
    int down_interruptible(struct semaphore *sem);
    int down_trylock(struct semaphore *sem);
    void up(struct semaphore *sem);

    5. 互斥体
    linux/mutex.h       kernel/mutex.c
    struct mutex mymutex;
    mutex_init(&mymutex);
    void fastcall mutex_lock(struct mutex *lock);
    int fastcall mutex_lock_interruptible(struct mutex *lock);
    int fastcall mutex_trylock(struct mutex *lock);
    void fastcall mutex_unlock(struct mutex *lock);

    总结
    1、信号量是进程级的,用于多个进程之间对资源的互斥。如果竞争失败,会发生进程上下文切换,当前进程进入休眠状态。
    2、自旋锁得不到锁时会在原地自旋一直到获取锁,它节省了上下文的切换时间,所以一般用于要保护的临界区访问时间比较短的时候,否则会降低系统效率。

    自旋锁和信号量选用原则
    1、临界区执行时间比较小时,采用自旋锁,否则使用信号量。
    2、信号量所包含的临界区包含可能引起阻塞的代码,而自旋锁要绝对避免在临界区使用阻塞代码。
    3、信号量运用进程上下文,若要运于中断中,应用down_trylock()方式进行,不能获取就立即返回,避免阻塞。

    参考:

    1. linux设备驱动开发详解 宋宝华

    2. linux并发控制

  • 相关阅读:
    byvoid
    soa文章摘抄
    也谈设计模式,架构,框架和类库的区别
    GoF设计模式三作者15年后再谈模式
    陈梓涵:我们为什么要学习设计模式
    陈梓涵:关于编程的胡扯
    hung task机制
    iscsi target tgt架构
    iscsi target IET架构
    ISCSI工作流程target和initiator
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/8596267.html
Copyright © 2011-2022 走看看