Chinaunix首页 | 论坛 | 博客
  • 博客访问: 553080
  • 博文数量: 99
  • 博客积分: 4010
  • 博客等级: 上校
  • 技术积分: 1117
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-23 15:17
文章分类

全部博文(99)

文章存档

2011年(4)

2010年(13)

2009年(82)

我的朋友

分类: LINUX

2009-07-07 19:07:18

为什么Linux 内核里面很多代码为了处理race condition(竞争条件),都加上了诸如cli sti这样的开关中断指令,这个问题貌似很不值得一提。在wait_on_buffer函数(如下代码所示)中,开关中断仅仅就是为了避免竞争条件和中断对临界代码的干扰?
view plaincopy to clipboardprint?
static _inline void wait_on_buffer(struct buffer_head * bh)  
 
{  
 
    cli();      // 关中断。  
 
    while (bh->b_lock)   // 如果已被上锁,则进程进入睡眠,等待其解锁。  
 
        sleep_on(&bh->b_wait);  
 
    sti();      // 开中断。  
 
static _inline void wait_on_buffer(struct buffer_head * bh)
{
 cli();  // 关中断。
 while (bh->b_lock) // 如果已被上锁,则进程进入睡眠,等待其解锁。
  sleep_on(&bh->b_wait);
 sti();  // 开中断。
}先还是来看看赵博的解释吧:
当进入可能引起竞争条件的代码区时,内核中就会用cli指令来关闭对外部中断的响应,而在执行完竞争代码区时内核就会执行sti指令已重新允许CPU响应外部中断。
在继续探讨之前,我觉得有必要在两个问题上达成共识,呵呵,比较严肃的说法。
1、在wait_on_buffer (包括其它同样有开关中断指令的程序代码) 它们都属于内核代码,也就是说当前这个进程是在内核态运行的。
2、内核态的进程不能抢占。
关于第一点,其实是很明白的。其它不说,就举两个例证:其一,我们执行sti这种特权指令,这个只能是内核态进程执行,不是一般用户权限就能执行的!要是随随便便是个进程都执行,可能系统很早就瘫了;其二,那就是我们读的代码都是内核代码,所以这个就是内核代码,有点强词夺理......
关于第二点,我想表达的意思是如果我们正在执行wait_on_buffer时,即使是没有关中断,我们也不会跳到其它进程,当然也不会有其他进程恰好修改了这个buffer中的属性。因为内核是非抢占的!比如这里的do_timer:
view plaincopy to clipboardprint?
if (!cpl)  
 
    return;         // 对于超级用户程序,不依赖counter 值进行调度。  
 
schedule (); 
 if (!cpl)
  return;   // 对于超级用户程序,不依赖counter 值进行调度。
 schedule ();大家可以看到如果是内核代码执行do_timer的话,他直接会返回,而不会执行任务切换!
所以我们可以总结下,进程执行wait_on_buffer时,是处于内核态,即使是没有关闭中断,不会调度到其它进程执行。唯一能干扰这种没有关闭中断的"裸等"只是一些其他的中断。但是就是为了防止这些其它的中断可能会改变临界区的一些关键变量,我们还是要关掉中断以防万一。
有同志不解,因为他没有在其他中断中发现可能会修改buffer从而导致临界区异常的代码,所以觉得Linux这样写不太妥。还是用赵博的一句话解释吧:
在这方面不能就事论事。如果有一个中断会修改呢?内核编程者总不能老是牵挂这方面的问题。
 
阅读(1298) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~