1.(1)什么是最理想的散列函数?
最理想的散列函数指的是使块能够均匀地分布在一组散列队列中,并且必须简单,以使性能不受损失。
(2)散列函数在它的计算中应该使用逻辑设备号吗?
我们知道,高速缓冲区所用的散列函数为:(设备号^逻辑块号)mod 307
通过设备号和逻辑块号能够唯一的定位一个数据块。
逻辑设备是在物理设备上划分和建立的。
2.在算法 getblk中,如果内核要从空闲表中摘下一个缓冲块,则他必须提高处理机优先级,以便在检查空闲表前封锁中断,为什么?
如果不进行中断的封锁,可能会造成同时会有其他进程也想从空闲表中获取缓冲块,按照默认的LRU算法,极有可能要取到相同的缓冲块。因此,要在对空闲表操作时要提高处理机优先级。
3.*在算法getblk中,在检查一个块是否正处于忙状态之前,内核必须提高处理机的优先级以封锁中断,为什么?
在《UNIX操作系统设计》书中看到linux内核态运行的进程是不可抢先的,这就意味着当在内核中运行的某一进程并不会被其他进程切换,仅当该进程进入了睡眠状态才会进行进程间切换操作,从而它解决了一互斥问题------保证在某一时刻最多只有一个进程在临界区内进行操作。
这与linux的抢占式内核有很大的不同。
这两个题目的做法主要是为了在执行修改操作时防止被中断,造成原子操作失败。
在察看了linux 0.12的内核源代码后,发现事实上,书中的getblk函数的实现与getblk算法存在很大的不同,在获得一个空闲的缓冲块的后,我们会把该块插到队尾中去,以保证LRU实现,可是在unix中就不会插回去。
现假设有两个进程,一个取名为A,另一个取名为B,并且这两个进程想取得同一个逻辑块,并假设两个进程所要的逻辑块并不在HASH列表中,所以他们必须将这个逻辑块从空闲列表中摘下一个空闲块,并把这个空闲块插入到相应的HASH列表中。 若现在在内核中进程A处于运行状态,而B处于就绪状态,当进程A执行程序到第240行的时候它的时间片已经被用完了,调度程序调度进程B从就绪状态转换成运行状态,进程A暂时退出运行状态。而进程B在它所分配的时间片内顺利地从空闲列表上取走了某一空闲块并且将这个空闲块插入到相应的HASH列表中,并且正在这个时刻进程B的时间片也用完了,这时调度程序调度进程转入运行状态,并且进程A继续从第243行运行的时候不就出问题了吗?
同时,根据Linux 0.11内核代码来看,它与《Unix操作系统设计》中的描述一致,也即在内核态运行时即使时钟中断来临并且时间片用完也不会切换掉,除非自愿。参见sched.c 第334行(by oldlinux redgrid版主),自己查看,果然如此。
4.在算法brelse中,如果缓冲区的内容无效,则把缓冲区加入到空闲表队列头部,如果缓冲区内容无效,该缓冲区应该出现在散列队列中?
首先,散列队列的作用是存放已经被分配磁盘块的缓冲块。
如果缓冲区的内容无效,则把缓冲区加入到空闲表队列头部,但并没有分配给磁盘块,因此不会加入散列队列中。
5.假设内核进行一个块的延迟写,当另一个进程从他的散列队列取那个块时会发生什么?从空闲表?
首先应该明确一些概念:
(1)延迟写,指的是把要写的数据先都放到内存里,等积累多了再一次性写到硬盘,降低对硬盘的读写损耗。
内核则更尽可能长时间地推迟物理地往磁盘上写。
(2)异步写,内核立即开始这一写磁盘的操作,但是不等候它的完成。
补充:同步与异步传输
(1)异步传输: 你传输吧,我去做我的事了,传输完了告诉我一声。
(2)同步传输: 你现在传输,我要亲眼看你传输完成,才去做别的事。
任何通信从广义上讲都是“同步“的。
当另一个进程从他的散列队列取那个块时,因为这个块正被使用,因此先不向磁盘中写入,可进行修改块中数据。
当一个进程从空闲表中去那个块时,要把缓冲块的内容先写到磁盘中,再把块发给进程。
6.*如果几个进程竞争一个缓冲块,内核担保没有一个进程永远睡眠,但是他不保证进程永远不会总也得不到使用缓冲区的机会。
重新设计getblk以保证一个进程最终能用上一个缓冲块。
7.重新设计算法getblk与brelse,使内核遵循“先进先出”的方案,和“最不经常使用”的方案。
“fifo”的方案: