我们接着上次说的,进程发起读写磁盘块的请求,将请求的盘块号放入请求队列中然后阻塞自己,而后磁盘驱动之后读/写完数据之后,再唤醒对应的阻塞的进程。
那么read_intr唤醒的机制是什么呢?其实就是信号量机制,这就要说到linux0.11里的隐藏队列,这点在李治军老师的视频中讲的很清晰:
void sleep_on(struct task_struct **p)
{
struct task_struct *tmp;
if (!p)
return;
if (current == &(init_task.task))
panic("task[0] trying to sleep");
tmp = *p;
//使自己变成队首进程
*p = current;
//阻塞自己
current->state = TASK_UNINTERRUPTIBLE;
schedule();
//唤醒下一个
if (tmp)
tmp->state=0;
}
原理就是:多个进程都在等着一个buffer的使用权,即在给bh->b_lock这个东西上锁的时候阻塞,然后每个进程加入到阻塞队列的时候,将自己插到队首,其实就是头插法。然后read_intr唤醒的时候,就唤醒队首,再由队首去唤醒队首的下一个,再由队首的下一个唤醒队首的下一个的下一个。。。。。以此类推,最终所有阻塞进程均被唤醒。
那么有如果多个进程同时被唤醒了,那么又会去竞争这个bh->b_lock这个锁,而显然进程优先级别较高的能抢到获取锁,而那些没有抢到锁的呢?继续头插法呗。那么假设所有进程优先级使相同的,那么其实不会出现有进程一直获取不到锁资源的情况,因为如果这一次这个进程是队末,那么下一次唤醒之后,这个进程就会变成队首了。。。即优先级较低的会在队列比较靠前的位置不会由于优先级低而永远获取不到锁资源,优先级高的则会由系统调度有限获得锁。