随书总结:《linux设备驱动开发》 宋宝华著
主要有:中断屏蔽;原子操作;自旋锁;信号量
1- 中断屏蔽:进入临界区前后关、开中断使能
2- 原子操作:在多进程(线程)的操作系统中不能被其它进程(线程)打断的操作就叫原子操作。原子操作是不可分割的,在执行过程中不会被任何其它任务或事件中断。 linux内核提供了一系列函数来实现内核中的原子操作,内核代码可以安全地调用它们而不被打断。位和整型变量原子操作都依赖底层CPU的原子操作实现,因此所有这些函数都与CPU的架构密切相关。
首先处理器会自动保证基本的内存操作的原子性。处理器保证从系统内存当中读取或者写入一个字节是原子的,意思是当一个处理器读取一个字节时,其他处理器不能访问这个字节的内存地址。奔腾6和最新的处理器能自动保证单处理器对同一个缓存行里进行16/32/64位的操作是原子的,但是复杂的内存操作处理器不能自动保证其原子性,比如跨总线宽度,跨多个缓存行,跨页表的访问。但是处理器提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性。
原子性不可能由软件单独保证--必须需要硬件的支持,因此是和架构相关的。在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。
总之认为原子操作是由CPU、硬件保证的就好。
3- 自旋锁:在获取资源前后获取取、释放锁,如果获取不到则一直等待,直到获取成功。用于保证临界区不受别的CPU和本CPU内的抢占进程打扰。但是可能受到中断下半部影响,这时可使用加入中断下半部的自旋锁
自旋锁的其他形式:读写锁;顺序锁;rcu读-拷贝-更新锁
注意事项:
a- 自旋锁是一种死等锁,使用与等待时间较短的场合
b- 自旋锁可能造成死锁,使用的临街区域不能有阻塞(copy_from_user()、copy_to_user()、kmalloc)())、递归调用等。
4- 信号量:信号量和自旋锁类似,只是在获取不到信号量会进入睡眠状态。信号量可用于同步,即A任务需要在B任务执行完才动作,A任务等待获取信号量,B任务执行完释放信号量。
注意事项:
a- 当临界区占用资源时间较长时适合使用信号量
b- 相较于自旋锁,信号量临界区可以使用阻塞代码
c- 信号量用于保存进程上下文,在中断、软中断中的临界资源不可使用信号量(信号量等待会使得等待任务睡眠),可使用自旋锁代替(部分资料中说中断中使用自旋锁前要禁止中断使能)。