内核锁机制简单介绍"/>
linux 内核锁机制简单介绍
在操作系统引入了进程概念,进程成为调度实体后,系统就具备了并发执行多个进程的能力,但也导致了系统中各个进程之间的
资源竞争和共享。另外,由于中断、异常机制的引入,以及内核态抢占都导致了这些内核执行路径(进程)以交错的方式运行。
对于这些交错路径执行的内核路径,如不采取必要的同步措施,将会对一些关键数据结构进行交错访问和修改,从而导致这些
数据结构状态的不一致,进而导致系统崩溃。因此,为了确保系统高效稳定有序地运行,linux必须要采用同步机制。
这些机制包括:原子操作、自旋锁、信号量、互斥体、完成变量、顺序锁等下面我介绍下常用的三种锁机制:
1、互斥锁 metux
以前内核唯一可以睡眠的锁是信号量(sem),metux是更简单睡眠锁,简单来说metux是信号量的一种简化,
因为多数用户可能只需要互斥,也就是说使用计数为1就可以了,而使用信号量相对就比较复杂。
mutex在内核中对应的数据结构mutex,其行为和使用计数为1的信号量类似,但是操作接口非常简单,也很高效
- mutex的初始化:
DEFINE_MUTEX(name); #静态初始化
mutex_init(&mutex); #动态初始化
二中初始化选其一;
- mutex的加锁和解锁:
mutex_lock(&mutex);
/*临界区*/
mutex_unlock(&mutex);
- 使用限制:只能在同一上下文中上锁和解锁,不适合内核同用户复杂的同步情况
2、自旋锁spinlock
自旋锁的最初设计目的是在多处理器系统中提供对共享数据的保护,自旋锁获取锁的过程,不会主动调用schedule()进行进程切换,而是占用cpu,
拼命的自旋,类似于while耗时操作。
自旋锁顾名思义,自旋,自旋锁只能被一个线程持有,如果另一个线程师徒获取被已经持有的自旋锁,那么线程会一直自旋占用cpu
--一直等到锁被释放,所以自旋锁的使用必须在使用时间短的地方。举例说明就是一个房间,只有一把钥匙,线程相当于人,房间同
时只能进一个人,房间空了,另一个人才能获取钥匙进去。
- spinlock初始化:
DEFINE_SPINLOCK(my_lock);
- 加锁和解锁:
spin_lock(&my_lock);
/*临界区*/
spin_unlock(&my_lock);
- 自旋锁的变种:
读写自旋锁rwlock:对照普通自旋锁,读写自旋锁允许多个读者进程同时进入临界区,交错访问同一个临界资源。
顺序自旋锁seqlock:允许任意数量的读取者同时进入临界区,但写入者必须进行互斥访问
- 使用限制:占用时间要短,中断中可使用,低开销加锁,不能用在睡眠的地方,变种的使用根据实际情况而定。
3、信号量·semaphone
信号量在创建时需要设置一个初始值,表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为1就变成互斥锁(Mutex)即同时只能有一个任务可以访问信号量保护的共享资源。一个任务要想访问共享资源,首先必须得到信号量,获取信号量的操作将把信号量的值减1,若当前信号量的值为负数,表明无法获得信号量,该任务必须挂起在该信号量的等待队列等待该信号量可用;若当前信号量的值为非负数,表示可以获得信号量,因而可以立刻访问被该信号量保护的共享资源。当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加1实现,如果信号量的值为非正数,表明有任务等待当前信号量,因此它也唤醒所有等待该信号量的任务。
- sem的初始化:
struct smeaphone name;
sema_init(&name,count); # name 是信号量变量名,count是使用数量
- 信号量的使用:
if(down_interrupt(&name)) #试图获取信号量
{}
/*临界区*/
up(&name); #释放信号量
- 自旋锁的变种:读写信号量(rwsem):内核提供了读入者信号量和写入者信号量,类似于读写自旋锁
互斥信号量:count=1,类似于mutex
- 使用限制:信号量中存在一个进程等待队列,未获取锁的进程将挂到该队列中,然后主动调用schedule()切换进程,让出cpu。
更多推荐
linux 内核锁机制简单介绍
发布评论