出于好奇,我想知道操作系统如何实现等待事件/句柄等的唤醒线程。
例如,假设OS线程不断扫描等待句柄列表,并在必要时执行相应的线程。并不是说我认为它以这种方式实现,因为它似乎效率低下。
我认为操作系统更有可能在包含与公开的等待句柄/事件相关联的同步原语的内存区域上设置硬件中断,然后当它们被触发时,它可以小心地安排线程,而不是安排它超过一次?
修改
实际上我想我更想具体考虑的是什么,但是没有完全找到唤醒睡眠核心以运行被阻止线程的情况?
答案 0 :(得分:3)
为了详细了解它,你必须参加一个操作系统课程(或至少购买一本关于这个主题的好书),因为它实际上涉及很多系统。
然而,基本上,它与线程状态的管理方式有关。线程是任何时候的几种不同状态之一:睡眠,准备或运行(通常更多,但这就是本讨论所需的全部内容)。处于运行状态的线程实际正在运行,并且线程中的代码正在执行。处于“休眠”状态的线程未运行,并且在决定下一个运行时,调度程序将跳过它。处于“就绪”状态的线程当前没有运行,但是一旦另一个线程进入休眠状态或它的时间片耗尽,调度程序可以自由选择安排该线程进入运行状态。
基本上,当你在互斥对象上调用“wait”时,操作系统会检查该对象是否已被另一个线程拥有,如果是,则将当前线程的状态设置为“sleeping”,并将该线程标记为“等待”在“那个特定的互斥体。
当拥有互斥锁的线程完成后,操作系统将遍历等待它的所有线程并将它们设置为“就绪”。调度程序下次出现时,它会看到一个“就绪”线程并将其置于“运行”状态。线程开始运行并检查它是否可以再次锁定互斥锁。这一次没有人拥有它,所以它可以继续它的快乐方式。
实际上,它要复杂得多,并且需要付出很多努力才能使系统尽可能高效(例如,避免唤醒线程只是为了让它立即恢复睡眠,以避免一个在互斥上挨饿的线程,其中有很多其他线程等待它等等)
答案 1 :(得分:1)
介绍性教科书的答案是,当一个线程等待事件发生时,它会被放到一个等待线程的队列中。该线程被标记为“等待”,因此操作系统的进程调度程序在查找要在处理器上运行的内容时会跳过该线程。最终(在正确的程序中),另一个线程将唤醒正在等待事件队列的一个或所有线程。然后线程被标记为“就绪”,操作系统再次开始调度它们。
当然,实际实施的方式相当棘手。我认为这是你真正的问题。对于Linux,您正在寻找的机制称为futex,它们太复杂了,我不能在这里做到公正。如果Wikipedia模糊了你的兴趣,请深入了解wiki页面底部的那些外部链接。
答案 2 :(得分:0)
我认为实现更简单,一个线程放在一个等待线程列表中(所有线程都在等待某些事件/句柄/互斥锁等等。当同步原语被唤醒时,所有线程都被移动到运行状态,清理列表。