临界区(critical section):对某个共享的数据结构(共享资源) 进行操作的程序片段
临界资源(critical resource):系统中某些资源一次只允许一 个进程使用,称这样的资源为临界资源或互斥资源或共享 变量
竞争条件(race condition):两个执行线程同时处于同一个临界区中。
同步(synchronization):避免并发和防止竞争条件被称为同步。
per-CPU variable
an array of data structures, one element per each CPU in the system
per-CPU就是每个CPU中的一个数组
a CPU should not access the elements of the array corresponding to the other CPUs; on the other hand, it can freely read and modify its own element
per-CPU数组内的才能访问特定CPU
the per-CPU variables can be used only when it makes sense to logically split the data across the CPUs of the system
当按照CPU分配数据的时候,per-CPU才会有意义
per-CPU variables provide protection against concurrent accesses from several CPUs, they do not provide protection against accesses from asynchronous functions (interrupt handlers and deferrable functions). In these cases, additional synchronization primitives are required.
保证一定程度并发
per-CPU variables are prone to race conditions caused by kernel preemption, both in uniprocessor and multiprocessor systems. As a general rule, a kernel control path should access a per-CPU variable with kernel preemption disabled.
a kernel control path gets the address of its local copy of a per-CPU variable, and then it is preempted and moved to another CPU: the address still refers to the element of the previous CPU
同CPU访问者,非内核抢占。可以将访问者移到其他CPU
Linux内核中最常见的锁:自旋锁(spin lock)
如果一个线程试图获得一个被争用的自旋锁,那 么该线程就会一直进行忙循环—旋转—等待锁重新可用
锁未被争用,请求锁的执行线程便立即得到它, 继续执行
普通的锁忙,会自己等会再去访问。而自旋锁会一直在原地等着
适合于加锁时间短的情况。
在中断处理程序中使用自旋锁(不能使用信号量, 因为信号量会导致睡眠)
自旋锁针对 SMP以及 本地内核抢占
写者优先:读时,写者可以进入;
其它与读写锁一样,写不阻塞读;读读ok, 写写no
优点:写者不必等待,读也不会被写阻塞
缺点:读者需要检查读到数据的有效性
使用场景:
允许多个读者和写者并发
不使用锁
性能好,但是对内存有一定开销,用在网 络层和虚拟文件系统中
适用于读多写少情况,如果写过多,写操作之间的同步开销会很大
就是写操作时,把要写的部分复制出来修改,然后找个合适的时间放回去
Linux提供两种信号量:
Linux中信号量是一种睡眠锁
使用信号量时锁的时间长一点是可以忍受的
持有信号量的代码可以被抢占
可以同时允许任意数量的锁持有者
信号量支持两个原子操作P() 和 V()
如果代码需要睡眠,使用信号量是唯一的选择。由于不 受睡眠的限制,使用信号量通常来说更加简单一些。
如果需要在自旋锁和信号量中作选择,应该取决于锁被 持有的时间长短。
需求 | 建议的加锁方法 |
---|---|
低开销加锁 | 优先使用自旋锁 |
短期锁定 | 优先使用自旋锁 |
长期加锁 | 优先使用信号量 |
中断上下文中加锁 | 使用自旋锁 |
持有锁是需要睡眠 | 使用信号量 |
所谓屏障,从处理器角度来说,是用来串行化读写操作的,从软 件角度来讲,就是用来解决顺序一致性问题
为什么使用屏障
Linux提供了确保顺序的指令称做屏障