常见的几种内核驱动涉及的锁,理解原子操作比较重要
对于arm来说,单条汇编指令都是原子的,多核smp也是,因为有总线仲裁所以cpu可以单独占用总线直到指令结束,多核系统中的原子操作通常使用内存栅障(memory barrier)来实现,即一个CPU核在执行原子操作时,其他CPU核必须停止对内存操作或者不对指定的内存进行操作,这样才能避免数据竞争问题。但是对于load update store这个过程可能被中断、抢占,所以arm指令集有增加了ldrex/strex这样的实现load update store的原子指令。
- 本质是执行原子操作,所以该操作完成之前其他执行单元不可能访问这个内存变量,
while循环一直检测该原子变量,无法进入sleep; - 单处理器非抢占内核下:自旋锁会在编译时被忽略;
- 单处理器抢占内核下:自旋锁仅仅当作一个设置内核抢占的开关;
- 多处理器下:此时才能完全发挥出自旋锁的作用,自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的竞争。
- 信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。最简单的信号量是只能取0和1的变量,这也是信号量最常见的一种形式,叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号量。大多数情况下讨论二进制信号量。
- 会进入sleep,不能在中断使用;
- 互斥体实现了"互相排斥"(mutual exclusion)同步的简单形式(所以名为互斥体(mutex))。互斥体禁止多个线程同时进入受保护的代码"临界区"(critical section)。因此,在任意时刻,只有一个线程被允许进入这样的代码保护区。mutex实际上是count=1情况下的semaphore。
- 会进入sleep,不能在中断使用;
- completion是内核中的一种同步机制,该机制主要借助等待队列实现同步,该同步机制是一种简单的同步机制。
- 会进入sleep,不能在中断使用;