内核机制之互斥与同步
来源:互联网 发布:井上真央松本润 知乎 编辑:程序博客网 时间:2024/05/16 16:13
并发来源:
1 中断 2 处理器的调度 3 多处理器的并发执行
local_irq_enable: 打开本地处理器中断,
对应于 local_irq_save:保存当前处理器状态
local_irq_disable: 关闭本地处理器中断
对应于 local_irq_restore
自旋锁
设置多处理器共享的全局变量锁V,并定义V =1 时为上锁状态,V=0时为解锁状态。当处理器A上的代码要进入临界区时,首先读取v的值,并判断v的值是否是0,如果v != 0,则其他处理器上的代码正在访问临界区代码,处理器A就处于忙等待状态。如果V == 0,那么处理器可以访问临界区代码,先把V设置1,进入临界区代码,当访问完临界区代码时,将v= 0。
关键是在 读取V,并判断V值 , 必须是原子操作
typedef struct raw_spinlock{ volatile unsigned int raw_lock;}raw_spinlock_t;typedef struct spinlock{ union{ struct raw_spinlock rlock; };}spinlock_t;static inline void spin_lock(spinlock_t *lock){ raw_spin_lock(&lock->rlock);}//宏preempt_disable,在定义CONFIG_PREEMPT即支持内核可抢占调度下,关闭调度器的可抢占性static inline void raw_spin_lock(raw_spinlock_t * lock){ preempt_disable();//关闭内核调度器的可抢占性 do_raw_spin_lock(lock); }static inline void spin_unlock(spinlock_t *lock){ raw_spin_unlock(&lock->rlock);}static inline void raw_spin_unlock(raw_spinlock_t *lock){ do_raw_spin_unlock(lock) preempt_eanble();}
spin_lock(spinlock_t *lock);并没有关闭中断,只关闭了可抢占性。所以有可能在处理器A获取自旋锁后,在临界区代码执行中,发生硬件中断,若中断处理函数中也需要对共享资源访问时,就会发生死锁状态。
static inline void spin_lock_irq(spinlock_t *lock){ raw_spin_lock_irq(&lock->rlock);}static inline void raw_spin_lock_irq(raw_spinlock_t *lock){ local_irq_disable(); preempt_disable(); do_raw_spin_lock(lock);}static inline void spin_unlock_irq(spinlock_t *lock){ raw_spin_unlock_irq(&lock->rlock);}static inline void raw_spin_unlock_irq(raw_spinlock_t *lock){ do_raw_spin_unlock(lock); preempt_enable(); local_irq_enable();}
拥有自旋锁的代码必须是原子的,不能睡眠。不能调用像kmallock 能够引起睡眠的函数等。
当知道一个自旋锁可能在中断上下文中使用时,要使用spin_lock_irq(spinlock_t *lock);
而spin_lock(spinlock_t *lock);只能在确定不会出现在中断上下文中时
与spin_lock_irq相似的宏 spin_lock_irqsave(spinlock_t *lock,unsigned long flag);
就是关闭中断前,将当前的处理器状态宝存在变量flag中
当调用spin_unlock_irqrestore释放锁时,将flag写回到寄存器中。
综上所述:spin_lock_irq与spin_unlock_irq
不管在多处理器系统与单处理器上,还是内核抢占与内核不可抢占上都有很好的可移植性。
调用自旋锁的进程切忌不能睡眠
自旋锁rwlock
允许任意的读取着同时进入临界区代码,但写入着必须互斥访问。如果一个进程想进入临界区进行读,则需要检查是否有写入着,如果有的话,就必须自旋,否则,可以进入临界区。如果一个进程想进入临界区进行写,则需要检查是否有写或者正在读的进程,若有,则需自旋等待。
void read_lock_irq(rwlock_t *lock);
void write_lock_irq(rwlock_t *lock);
信号量(semaphore)
相对与自旋锁,信号量最大的区别是信号量允许调用的进程可以进行睡眠,也就是可能丧失对处理器的控制,出现进程切换。
struct semaphore{ spinlock_t lock; unsigned int count;//允许进入临界区的个数 struct list_head wait_list;//不能获得信号量的进程投入到等待队列中};//semaphore initstatic inline void sema_init(struct semaphore *sema,int val);//down operationint down_interruptible(struct semaphore *sem){ unsigned long flag; int result = 0; spin_lock_irqsave(&sem->lock,flag); if( likely(sem->count > 0) ) { sem->count--; } else { result = __down_interruptible(sem); } spin_unlock_irqrestore(&sem->lock,flag); return result;}//__down_interruptible cal在内部调用__down_common(struct semaphore *sem,long state,long timeout);//state = TASK_INTERRUPTIBLE//timeout = LONG_MAXstatic inline int __down_common(struct semaphore *sem,long state,long timeout){ struct task_struct *task = current; list_add_tail(&waiter.list,&sem->list); waiter.task = task; waiter.up = 0; while(1) { if(signal_pending_state(state,task)) goto interrupted; if(timeout <= 0) goto timeout; __set_task_state(task,state); spin_unlock_irq(&sem->lock); timeout = schedule_out(timeout); spin_lock_irq(&sem->lock); if(waiter.up) return 0; }timeout: list_del(&waiter.list); return -ETIME;interrupted: list_del(&waiter.list); return -EINTER;}
//具体的事例代码如下:struct semaphore demosem;sem_init(&demosem,5);if(down_interruptible(&demosem)) return -ERESTARTSYS;
void up(struct semaphore *sem){ unsigned long flag; spin_lock_irqsave(&sem->lock,flag); if( list_empty(&sem->list) ) sem->count++; else __up(sem); spin_unlock_irqrestore(&sem->lock,flag);}static inline void __up(struct semaphore *sem){ struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, struct semaphore_waiter,list); list_del(&waiter->list); waiter->up = 1; wake_up_precess(waiter->task);}
信号量的用途
实现互斥 机制,也就是初始化时值 1,之允许一个进程进入临界区。
DECLARE_MUTEX(name) struct semaphore name = _SEMAPHORE_INITIALIZER(name,1)
DECLARE_MUTEX(demosem);void demo_write(){ if(down_interruptible(&demosem)) return -ERESTARTSYS; //进入临界区代码 up(&demosem);}
互斥锁Mutex
completion机制
struct completion{ unsigned int done;};
- 内核机制之互斥与同步
- 全面解析Linux内核的同步与互斥机制
- 解析Linux内核的同步与互斥机制(一)
- 解析Linux内核的同步与互斥机制(二)
- 解析Linux内核的同步与互斥机制(三)
- 解析Linux内核的同步与互斥机制(四)
- 解析Linux内核的同步与互斥机制(五)
- 解析Linux内核的同步与互斥机制(六)
- 解析Linux内核的同步与互斥机制(七)
- Linux内核中的互斥与同步机制
- Linux内核同步与互斥--锁机制
- Linux内核中的互斥与同步机制
- JAVA多线程机制之同步与互斥
- 全面解析Linux内核的同步与互斥机制--同步篇
- 全面解析Linux内核的同步与互斥机制--同步篇 收藏
- 全面解析Linux内核的同步与互斥机制--同步篇(转)
- 全面解析Linux内核的同步与互斥机制--同步篇
- 全面解析Linux内核的同步与互斥机制--同步篇
- HTTP详解
- $.ajax和java后台实现用户登录的功能
- redis异常解决:jedis.exceptions.JedisDataException: ERR Client sent AUTH, but no password is set
- iOS开发-基础:Objective-c单例模式的正确写法
- 斐波那契数列
- 内核机制之互斥与同步
- java 解析没有根节点的类xml文件
- question_014-JAVA之Map
- 编程珠玑 5.10调试
- htonl() htons()及inet_ntoa() inet_addr()的用法
- iOS 蓝牙 4.0 开发
- GIF 4.0+版本sig生成方法分享
- NavigationDrawer和NavigationView-Android M新控件
- 自动问答技术简介