3同步和锁机制
并发的可能情形:
1,中断
2,软中断
3,内核抢占
4,对称多处理
5,睡眠
死锁的避免
1,顺序加锁
2,不要重复请求同一个锁
3,设计力求简单
自旋锁和信号量是内核中主要的同步机制,用于保证对临界区的唯一性排他访问。如果进程不能获得自旋锁,将自旋等待,而不能获得信号量则睡眠。其中在单处理器系统中,自旋锁只是禁止内核抢占。
自旋锁和信号量的不同:
1,自旋锁是轻量级锁,信号量适用于长时间等待,其维护等待队列,上下文切换开销比较大
2,自旋锁能用于中断上下文,信号量只能用于进程上下文
3,在持有自旋锁时不能睡眠,也就是占用信号量的同时不能拥有自旋锁
4,需要和用户空间的代码同步时,信号量是唯一的选择
自旋锁:
spin_lock_init()
spin_lock()
spin_lock_irq()
spin_lock_irqsave()
信号量:
16 struct semaphore {
17 spinlock_t lock; //这个lock用于保护struct semaphore
18 unsigned int count;
19 struct list_head wait_list;
20 };
sema_init()
down()
53 void down(struct semaphore *sem)
54 {
55 unsigned long flags;
56
57 spin_lock_irqsave(&sem->lock, flags);
58 if (likely(sem->count > 0))
59 sem->count--;
60 else
61 __down(sem);
62 spin_unlock_irqrestore(&sem->lock, flags);
63 }
如果count>0,则获得这个信号量,成功返回。如果《=0,则进入__down的处理
207 struct task_struct *task = current;
208 struct semaphore_waiter waiter;
209
210 list_add_tail(&waiter.list, &sem->wait_list);
211 waiter.task = task;
212 waiter.up = 0;
213
214 for (;;) {
215 if (signal_pending_state(state, task))
216 goto interrupted;
217 if (timeout <= 0)
218 goto timed_out;
219 __set_task_state(task, state);
220 spin_unlock_irq(&sem->lock);
221 timeout = schedule_timeout(timeout);
222 spin_lock_irq(&sem->lock);
223 if (waiter.up)
224 return 0;
225 }
将进程添加到sem的等待队列中,设置进程的状态为TASK_UNINTERRUPTABLE或TASK_INTERRUPTABLE,调用schedule()进行进程的切换。
而up()则把第一个进程从等待队列中删除,并wake up()
up()
178 void up(struct semaphore *sem)
179 {
180 unsigned long flags;
181
182 spin_lock_irqsave(&sem->lock, flags);
183 if (likely(list_empty(&sem->wait_list)))
184 sem->count++;
185 else
186 __up(sem);
187 spin_unlock_irqrestore(&sem->lock, flags);
188 }
256 static noinline void __sched __up(struct semaphore *sem)
257 {
258 struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
259 struct semaphore_waiter, list);
260 list_del(&waiter->list);
261 waiter->up = 1;
262 wake_up_process(waiter->task);
263 }
阅读(1381) | 评论(2) | 转发(0) |