linux并发控制

来源:互联网 发布:欧洲五代机 知乎 编辑:程序博客网 时间:2024/04/30 00:17

一.概念

1.并发(concurrency)指多个执行单元同时,并行被执行。

2.并发的执行单元对共享资源,(比如说,硬件资源,全局变量,静态变量等)访问很容易导致竞态(race conditions)。

举个简单事例,古代皇帝有很多妃子,皇帝第一个时辰是宜妃的,第二个时辰是萱妃,最后时间是皇后的,这是原来正常的顺序。假如宜妃让皇帝赖床了,萱妃不爽了,然后萱妃时间冲突了,皇后也不爽了,竞争就产生了,然后就是一部血雨腥风的后宫大戏。(呃,清宫剧,广告太厉害了,连我不看的都影响了)在linux中我们不需要这种大戏。

3.造成竞态的主要原因:

1.对称多处理器(SMP)

    多个CPU使用共同的系统总线,访问共同的外设和存储器。

2.单CPU内进程与抢占它的进程

    高优先级抢占低优先级

3.中断与进程之间

4.中断与中断之间

4.解决方案

保证对共享资源的互斥访问。

访问共享资源的代码区域称为临界区。

方法:中断屏蔽,原子操作,自旋锁,信号量等

 

二.用法

1.中断屏蔽

    单CPU范围内避免竞态的一种简单而省事的方法

     一旦中断屏蔽,进程调度不会发生,中断和进程之间的并发不会发生

    缺点:很多硬件事件不能得到及时处理,可能造成数据丢失,系统崩溃。

    为什么呢,因为linux的异步I/O,进程调度等都依赖于中断,在屏蔽中断期间所有的中断都无法得到处理。

    注意:单独使用中断屏蔽不是一个好方法,宜与自旋锁联合使用

用例

local_irq_disable();

...临界区...

local_irq_enable();

2.原子操作

    在执行过程中不会被别的代码路径所中断的操作

    函数分两类,分别针对 位和整型变量 

用例:

static atomic_t XXX = ATOMIC_INIT(1);    //定义原子变量并初始化为1

if(!atomic_dec_and_test(&XXX))    // atomic_dec_and_test 测试减一是否为零,为零返回true

{

atomic_inc(&XXX);

return -EBUSY;

}

atomic_inc(&XXX);    //释放设备

 3.自旋锁

自旋锁有“加锁”和“解锁”两种状态。

我的理解是,“加锁”一直在寻求“解锁”,“解锁”马上会寻求“加锁”,并原地打转,所以加锁位置的代码进入临界区执行,直到解锁。

注意

    1.占用临界区的时间必须短;

    2.拥有自旋锁期间所在的CPU进程抢占被关闭

    3.占有自旋锁期间不能调用引起阻塞的函数(原子上下文)比如:copy_from_user(), kmalloc(), msleep()

    4.自旋锁可以被用于中断上下文

特殊化自旋锁:读写自旋锁,顺序锁,RCU锁

用例:

spinlock_t lock;    //定义自旋锁

spin_lock_init(&lock);    //初始化自旋锁

spin_lock(&lock);    // 获取自旋锁

...临界区...

spin_unlock(&lock)

4.信号量

与自旋锁类似,不同的是,当获取不到信号量时,进程不会原地打转而是进入休眠等待状态。

注意

    1.信号量是进程级的,当进程占用资源时间较长时,信号量是较好的选择(因为进程上下文切换的开销很大)

    2.临界区可以包含可能引起阻塞的代码,可以进入休眠

    3.信号量不能被用于中断上下文

用例

DECLARE_MUTEX(XXX_sem);    //定义一个 信号量并初始化为1

down(&XXX_sem);    //获取信号量

...临界区...

up(&XXX_sem);     //释放信号量

0 0
原创粉丝点击