内核同步机制
1.信号量/原子操作
2.自旋锁/互斥锁
3.内核屏障/RCU
1.信号量:适合所有CPU,加锁时阻塞等待(睡眠)
原理:当内核控制路径试图获取内核信号量保护的忙资源时,相应的资源被释放时,进程才再次变得可运行.
使用限制:只有可以睡眠的函数才能获取内核信号量.中断处理程序和可延迟函数都不能使用内核信号量
2.原子操作:所有CPU,对一个计数器原子地"读-修改-写"的指令
原理:是借组于汇编指令中对"读-修改-写"具有原子性的汇编指令来实现.
3.自旋锁:所有CPU,加锁时忙等
原理:如果一个内核控制路径发现所有请求的自旋锁已经由运行在另一个CPU上的内核"锁着",就反复执行循环指令,直到锁被释放,自旋锁用于保护内核抢占灵界区,在单处理器中作用仅是禁止或启用内核抢占功能.
4.内存屏障:本地CPU或者所有CPU,免费指令重新排序
原理:使用内存屏障原语确保在原语之后的操作执行时,原语之前的操作已经完成.
二.Linux内核源码分析
1.信号量:进程间对共享资源的互斥访问是通过"信号量"机制来实现的.Linux内核提供两个函数down(),up()用于分别实现P,/V操作.
信号量在内核中的定义:
struct semaphore {
raw_spinlock_t lock;
unsigned int count;//信号量中的那个量,代表可用资源数量,绝对值可用正在等待的资源,0可用没有可被使用的资源.
struct list_head wait_list;//存放等待链表地址,链表中包含正在等待这个资源的所有随眠的进程
};
down(),up()函数主要应用在文件系统和驱动程序之后,把药保护的灵界区放在这两个函数中间.该函数用嵌入汇编进行实现.
down();
临界区
up();
2.原子操作:
避免干扰最简单方式就是保证操作的原子性,即操作必须在一条单独的指令内执行.拥有两种类型原子操作 :
a.位图操作.在内核很多地方用到位图,如内存管理中对空闲的管理,位图还有一个广泛用途就是简单的加锁.
b.算术操作.有时位操作不方便,取而代之的是需要执行算术操作,如加/减/加减操作数据结构当中引用计数域count,如node结构.
typedef struct {volatile int counter,}atomic_t ;
ATOMIC_INIT ,atomic_read,atomic_set,atomic_add,atomic_sub,atomic_inc,atomic_dec,atomic_sub_and_test
Linux为什么需要同步机制:
操作系统引入进程,进程成为调度实体,系统就具备并发执行多个进程的能力,但页导致系统中各个进程之间资源共享和竞争.另外,由于中断/异常机制的引入,内核态抢占都导致这些内核执行路径以交错方式运行(不采取必须同步操作,将会对一些关机数据结构进行交错访问或修改,导致这些数据结构状态不一致,导致系统崩溃).为了确保系统高效有序进行,必须采取同步机制.
Linux并发源于:中断处理,内核态抢占,多处理器并发.