线程如何在禁用中断的情况下进入睡眠状态? [英] How does threads sleep with interrupt disabled?

查看:170
本文介绍了线程如何在禁用中断的情况下进入睡眠状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解以下代码的工作方式.这直接来自我的专业讲座幻灯片.这个P()和V()函数是我们在类(OS161)中使用的OS中信号量实现的一部分.我认为您可能需要了解OS161才能回答我的问题,因为它已被广泛使用,希望有人可以回答这个问题.

我对本代码的理解和讲义:
X:P()函数的流程
1.当线程调用P()时,我们禁用中断
2.检查sem-> count
是否有可用资源 3.a)如果count为0,那么我们就去睡觉
3.b)如果count!= 0,则我们递减count并允许调用线程继续到关键部分
4.启用中断
Y:V()函数的流程
1.当线程调用V()时,我们禁用中断
2.增加计数器,这意味着现在有1种可用资源可供抓取
3.现在,我们继续唤醒所有发送给P()进入睡眠状态的线程,因为在该线程试图获取对关键部分的锁定时没有足够的资源
4.启用中断

I am trying to understand how the code below works. This is straight out of my profs lecture slides. This P() and V() function is the part of semaphore implementation in the OS that we use in class (OS161). I think you might need understanding of the OS161 to answer my question, since its widely used, hopefully some one can answer this questions.

My understanding of this code with lecture notes:
X:Flow of the P() function
1. When a thread call P(), we disable interrupt
2. check if we have any resources available on sem->count
3.a) if count is 0 then we go to sleep
3.b) if count != 0 then we decrements count and allow the calling thread to continue to critical section
4. Enable Interrupt
Y:Flow of the V() function
1. When a thread call V(), we disable interrupt
2. Increment the counter, implying that now there is 1 more resource available to grab
3. Now we go ahead and wake up all the thread that we sent to sleep in P(), because there was not enough resources available at the time the thread tried to grab a lock to a critical section
4. Enable Interrupt

我的问题:
1.禁用中断"部分是禁用特定线程上的中断还是禁用所有中断? 2.在V()函数上,当我们唤醒所有线程时,在P()函数的while循环内休眠的线程开始执行while循环.在演讲中,它说一个线程抓住了锁,其余的就回到睡眠状态.我的问题是,为什么"sem-> count == 0"条件对于其他线程不会求为假,而只能为一个.

My Problems:
1. Does "disable interrupt" section disable interrupt on a particular thread or does it disable all the interrupts?
2. On V() function when we wake up all the threads, the thread slept inside the while loop in P() function start to execute the while loop. In the lecture it says one thread grab the lock and rest go back to sleep. My question is why "sem->count == 0" condition doesn't evaluate to false to other threads but only one.

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

I really want to know how does the interrupt disable part works. which is my first question. Does it stops thread scheduler?, does it stop context switch in the system?

为什么线程在禁用中断的情况下进入睡眠状态?因为这样会丢失I/O完成的信号和其他东西,这不是很危险吗?

Why does the thread goes to sleep with interrupt disable? isn't that dangerous, since it can miss I/O finished signals and other things?

    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;
    }

谢谢.

推荐答案

CPU对线程一无所知,它们只是在软件中实现的逻辑/抽象概念.但是CPU确实知道中断,它们是真实的,每当某个设备发出中断时,CPU就会停止执行其已执行的任何程序,并开始执行专用于处理此特定中断的例程.完成后,该例程会发出中断处理完成的信号,并且CPU将恢复执行中断处理例程所抢占的所有内容.

The CPU knows nothing about threads, they are just a logical/abstract concept implemented in software. But the CPU does know about interrupts, they are real, and whenever one comes in from some device, the CPU stops executing whatever it has been executing and starts executing the routine dedicated to handling this particular interrupt. Once done, the routine signals completion of interrupt handling and the CPU resumes execution of whatever was preempted by the interrupt handling routine.

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

If the preempted code belonged to a thread, so be it. If it was another interrupt handling routine, fine too.

就在中断处理例程开始之前,CPU在堆栈或其他地方保存了一些执行上下文(一些通用的,也许还有一些控制/系统寄存器),因此例程可以将它们用于其自己的目的,然后在例程结束时,CPU从存储寄存器的位置恢复这些寄存器,就好像从中断代码的角度来看什么都没有发生.如果例程更改了这些寄存器,则CPU将在其他地方恢复执行,而不是在中断前最后一次执行的地方.

Just before the interrupt handling routine starts, the CPU saves some of the execution context (a few general-purpose and maybe a few control/system registers) either on the stack or somewhere else, so the routine can use them for its own purposes, and then at the end of the routine the CPU restores those registers from wherever they were stored, as if nothing ever happened from the point of view of the interrupted code. If the routine alters those registers, the CPU will resume execution somewhere else, not where it was executing the last time before the interrupt.

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

So, there, you can use interrupts to switch execution between the various pieces of code, threads or what have you. In fact, this is exactly how many schedulers work. They receive periodic interrupts from a timer and in the interrupt handler they save the context of the preempted code (e.g. thread A) in memory and load the context of another preempted code (e.g. thread B) from memory and return thereby continuing execution in another thread.

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

If you disable those timer interrupts, periodic thread scheduling/switching will be disabled as well. Interrupts affect the entire CPU and the currently executing thread (or whatever it is) and by induction they affect all threads.

知道了吗?

现在,如果系统中有线程,则总是至少有一个线程可以执行.这是因为CPU需要执行某些操作,它不能只是停止并等待线程无处到达(毕竟,CPU创建线程并使它们可运行并运行).为此,系统中有一个伪线程(或不是伪线程),它具有较低的优先级,并且几乎不执行任何操作,永远循环,并可能告诉CPU它可能会切换到低功耗状态或暂停,直到出现中断为止中断将终止低功耗模式并导致代码继续执行.

Now, if there are threads in the system, there's always at least one thread that can execute. That's because the CPU needs to execute something, it can't just stop and wait for a thread to arrive from nowhere (after all, it's the CPU who creates threads and makes them runnable and runs them). For this purpose there's a dummy (or not so dummy) thread in the system that has a low priority and does pretty much nothing, looping forever and perhaps telling the CPU that it may switch to a lower power state or halt until an interrupt comes in. An interrupt would end the low-power mode and cause the code to continue execution.

因此,当线程在信号量或某些其他同步原语上阻塞时,调度程序仅选择另一个线程来执行.如果所有线程都被阻止,则将选择虚拟线程.

So, when a thread blocks on a semaphore or some other synchronization primitive, the scheduler simply picks another thread to execute. If all threads are blocked, the dummy thread is selected.

在您的代码中,中断会在很短的时间内被禁用,而内核代码正在处理各种全局变量(例如,阻塞/睡眠和就绪线程的列表).那很正常您不想要这里的比赛条件.当调度程序选择另一个线程执行并继续执行时,重新启用中断.

In your code, interrupts get disabled for a short period of time, while the kernel code is manipulating the various global variables (e.g. the lists of blocked/sleeping and ready threads). That's normal. You don't want race conditions here. Interrupts are re-enabled when the scheduler picks another thread to execute and proceeds to execute it.

观察到当某个当前线程完成睡眠时(例如,当其他某个线程将其唤醒时),它总是启用中断:

Observe that when an at-some-point-current thread finishes sleeping (e.g. when some other thread wakes it up), it always enables interrupts:

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

以这种方式阻塞的每个线程在唤醒并由调度程序选择运行时都会导致再次启用中断.

Every thread blocked in this manner will cause interrupts to be enabled again when it's woken up and chosen by the scheduler to run.

只需考虑一下.您在2个(或多个)线程中具有2个(或更多)上述或类似代码的实例.当一个人进入thread_sleep()或类似函数时,其他线程从其thread_sleep()或类似函数中退出并重新启用中断.

Just think about it. You have 2 (or more) instances of the above or similar code in 2 (or more) threads. When one enters thread_sleep() or a similar function, some other thread comes out of its thread_sleep() or a similar function and re-enables interrupts.

遵循以下路径的代码和注释:

Follow the code and comments along this path:

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

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

至于信号量,我现在不愿意做更多的代码分析.您应该尝试自己弄清楚它,除非有人鸣叫并掩盖了它.

As for the semaphore count, I'm not willing to do more code analysis now. You should try to figure it out yourself, unless someone else chimes in and covers it.

这篇关于线程如何在禁用中断的情况下进入睡眠状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆