如果多个进程或是线程同时想改变一个变量 或说程序间的运行结果精确依赖于它的执行顺序 这种情况就叫做竞态
为了让程序的运行结果可控 于是发明了同步机制
在Linux/Unix下
进程间的同步方式有管道,消息队列,信号量,信号,共享内存
线程间的同步工有互斥锁,条件变量,
那在内核开发中 也需要有同样的同步机制
内核开发中与应用开发的区别是
内核开发更重视高效率 并且 对可重入性的要求更高
操作系统中只有一份内核的映象 内核模块可以访问系统所有资源并修改 影响整个系统
而应用程序则每个进程都有自己的地址空间,每个进程的活动不影响其它进程
内核是中断式驱动的 每一步都需要考虑可重入性
进程除非指定信号处理程序 否则是可以自己控制程序的运行
另外对多cpu的情况 必须保证内核中变量的同步 而多CPU对进程来说已经被抽像了 它不必了解
下面把内核中使用的内核锁机制写一下
第一个是关中断与开中断
disable_irq(unsigned int irq)//等待到irq的处理已经完成才返回
disable_irq_nodync(unsigned int irq)//返回前并不保证irq的处理函数已经完成
enable_irq(unsigned int irq)
原子化操作
如果指令的执行是一次完成 中间没有中断 我们把它叫做原子化操作
原子操作是一个atomic_t类型的变量,这个类型的具体实现是什么对外面来说并不需要关心
因为内核已经定义了一组操作函数
atomic_t类型的有效值是24bit,注意
所有函数的定义都在asm/atomic.h
CODE
atomic_read — read atomic variable
atomic_set — set atomic variable
atomic_add — add integer to atomic variable
atomic_sub — subtract the atomic variable
atomic_sub_and_test — subtract value from variable and test result
atomic_inc — increment atomic variable
atomic_dec — decrement atomic variable
atomic_dec_and_test — decrement and test
atomic_inc_and_test — increment and test
atomic_add_negative — add and test if negative//如果<0返回true,>=0为false
带test后缀的函数,判断操作后结果是不是==0,如果结果==0那返回true
不然返回false
自旋锁
自旋锁为需要快速完成的操作提供了一个简单的机制,当它发现锁已被锁定时,会循环等待一直到可用,为变量的同步访问提供了机制
与信号量相比,自旋锁的速度更快 开销更少
它的定义在asm/spinlock.h
类型为spinlock_t
有一个快速初始化宏SPINLOCK_UNLICKED;
它提供的函数如下
CODE
void spin_lock_init(spinlock_t *sl); //可使用sl = SPINLOCK_UNLICKED;代替
int spin_is_locked(spinlock_t *sl); //检测是不是已被锁定
void spin_lock(spinlock_t *sl);//锁定
void spin_unlock(spinlock_t *sl);//解锁
int spin_trylock(spinlock_t *sl); /* returns 0 if succeeded */
//下面在需要禁止irq时使用,当然速度会降低
spin_lock_irqsave(spinlock_t*sl,unsigned long flags)
spin_lock_irqrestore(spinlock_t*sl,unsigned long flags)
读写锁
读写锁用于更细的锁定
类型为rwlock_t
也定义在spilock.h
初始化变量为RELOCK_UNLOCKED
函数
CODE
read_lock(rwlock_t*)
read_lock_irqsave(rwlock_t*,unsigned long flags)
read_unlock(rwlock_t*)
read_unlock_irqrestore(rwlock_t(,unsigned long)
write_lock...
功能与spinlock的操作相似
信号量
信号量的功能与应用程序开发中的差不多
类型为semaphore
定义在semaphore.h
CODE
void sema_init(struct semaphore *sem, int val); /* alternative to DECLARE_... */
void down(struct semaphore *sem); /* may sleep */
int down_interruptible(struct semaphore *sem); /* may sleep; returns -EINTR on interrupt */
int down_trylock(struct semaphone *sem); /* returns 0 if succeeded; will no sleep */
void up(struct semaphore *sem);
内核锁
内核锁用于smp系统中,保证当前只有一个cpu运行 现在它的功能已被细分到各子锁了 也不再那么有用 但是在需要的时候 还是应该想到它
用法很简单 就两个函数
CODE
lock_kernel();
/* critical region ... */
unlock_kernel();
可抢占式锁定
新内核的进程调度方式增加了可抢占性 它充许更高优先级的进程运行,甚至当前进程仍在内核中运行
这时给锁定带来了一定的困难 因为锁只是针对某个cpu而言的
如果你希望使进程不可以抢占运行 那可以使用下面两个函数
preempt_disable()
preempt_enable()
它们可以调用多次,当然你加了n次锁也必须解n次锁
阅读(1450) | 评论(0) | 转发(0) |