2013-02-23 75 views
1

我想了解下面的代码是如何工作的。这是我的讲座幻灯片中的直接内容。这个P()和V()函数是我们在类(OS161)中使用的操作系统中信号量实现的一部分。我想你可能需要了解OS161来回答我的问题,因为它被广泛使用,希望有人能回答这个问题。

我这个代码与讲义的理解:
X:在P()函数
1.当一个线程调用P(),我们禁止中断
2.检查,如果我们有流程如果count为0,那么我们去睡
3.b)如果count!= 0,那么我们递减计数并允许调用线程继续到临界区
4.启用中断
Y:在V()函数
1.当一个线程调用V(),我们禁止中断
2.增加计数器,这意味着现在有1个更多的可用资源,抢
3.现在的流量我们继续前进,唤醒所有我们发送的P()睡觉,因为没有足够的可用资源的时候线程试图抓住一个锁到了关键部分的螺纹
4.启用中断
线程如何在禁用中断的情况下进入睡眠状态?

我的问题:
1.是否“禁用中断”部分禁用特定的中断广告还是禁用所有的中断?
2.在V()函数唤醒所有线程时,线程睡在P()函数的while循环内,开始执行while循环。在讲座中说,一条线抓住锁,休息回去睡觉。我的问题是为什么“sem-> count == 0”条件不计算为其他线程,而只有一个。

我真的很想知道中断禁用部分是如何工作的。这是我的第一个问题。它会停止线程调度吗?它会停止系统中的上下文切换吗?

为什么线程在中断禁用状态下进入睡眠状态?是不是很危险,因为它可能会错过I/O完成的信号和其他东西?

P(sem) { 
     Disable interrupts; 
     while (sem->count == 0) { 
     thread_sleep(sem); /* current thread 
           will sleep on this sem */ 
     } 
     sem->count--; 
     Enable interrupts; 
    } 
    V(sem) { 
     Disable interrupts; 
     sem->count++; 
     thread_wakeup (sem); /* this will wake 
     up all the threads waiting on this 
        sem. Why wake up all threads? */ 
     Enable interrupts; 
    } 

谢谢。

回答

5

CPU对线程一无所知,它们只是一个在软件中实现的逻辑/抽象概念。但是CPU确实知道中断,它们是真实的,并且每当有人从某个设备进入时,CPU就停止执行它执行的任何内容,并开始执行专用于处理该特定中断的例程。一旦完成,例程就表示完成了中断处理,并且CPU恢复中断处理例程先占的任何执行。

如果被抢占的代码属于一个线程,那就这样吧。如果是另一个中断处理程序,那也可以。

就在中断处理例程开始之前,CPU会在堆栈或其他地方保存一些执行上下文(一些通用的和可能的一些控制/系统寄存器),以便例程可以将它们用于它自己的目的,然后在例程结束时,CPU从这些寄存器的任何地方恢复这些寄存器,就好像从中断代码的角度来看什么都没发生过一样。如果该例程改变这些寄存器,则CPU将在其他地方恢复执行,而不是在中断之前最后一次执行的地方。

因此,在那里,您可以使用中断在各种代码,线程或您之间切换执行。事实上,这正是有多少调度程序工作。他们从计时器接收到周期性中断,并在中断处理程序中将被抢先代码(例如线程A)的上下文保存在内存中,并从内存中加载另一个先占代码(例如线程B)的上下文并返回,从而在另一个线程中继续执行。

如果禁用这些定时器中断,定期线程调度/切换也将被禁用。中断影响整个CPU和当前正在执行的线程(或任何它),并通过归纳影响所有线程。

Got it?

现在,如果系统中有线程,总是至少有一个线程可以执行。那是因为CPU需要执行一些东西,它不能停下来等待一个线程从无处到达(毕竟,CPU是创建线程并使它们可运行并运行它们的)。为此,系统中有一个虚拟线程(或不是虚拟线程),它具有低优先级,并且几乎没有任何操作,可以永久循环,也许可以告诉CPU它可以切换到低功耗状态或停止,直到出现中断。中断将结束低功耗模式并导致代码继续执行。

所以,当一个线程阻塞信号量或其他同步原语时,调度器只需选择另一个线程来执行。如果所有线程都被阻塞,则选择虚拟线程。在你的代码中,当内核代码操纵各种全局变量(例如阻塞/睡眠和就绪线程列表)时,中断会在短时间内被禁止。这很正常。这里你不需要比赛条件。当调度程序选择另一个线程执行并继续执行时,中断将重新启用。

观察的是,当在-一些点电流线程完成睡眠(例如,当一些其他线程唤醒它),它总是允许中断:

spl = splhigh(); // disable interrupts 
while (sem->count==0) { 
    thread_sleep(sem); // context switch (to another thread and then back) occurs here 
} 
sem->count--; 
splx(spl); // <-- re-enable interrupts here 

每个线程阻塞以这种方式会引起中断当它被唤醒并由调度程序选择运行时再次启用。

想想吧。在2个(或更多)线程中,您有2个(或更多)以上或类似代码的实例。当输入thread_sleep()或类似的函数时,其他线程会从其thread_sleep()或类似的函数中出来并重新启用中断。

按照沿着这条道路的代码和注释:

P()
    thread_sleep()
        mi_switch()
            md_switch()
                mips_switch()

至于信号计数,我不愿意现在要做更多的代码分析。你应该尝试自己弄清楚,除非有人在其中加入并覆盖它。

相关问题