我不能直接添加到David,templatetypedef等给出的优秀答案 - 如果您想避免线程间通信延迟和资源浪费,请不要使用sleep()循环执行线程间通信。
抢占式调度/调度:
在CPU级,中断是关键。在发生导致其代码输入的中断之前,操作系统什么也不做。需要注意的是,在操作系统方面,中断有两种形式 - “真正的”硬件中断,导致要运行的驱动程序和“软件中断” - 这是OS系统从已经运行的线程调用可能会导致该组运行的线程改变。按键,鼠标移动,网卡,磁盘,页面错误都会产生硬件中断。 wait和signal函数和sleep()属于第二类。当硬件中断导致驱动程序运行时,驱动程序会执行设计要执行的任何硬件管理。如果驱动程序需要向操作系统发出某个线程需要运行的信号(可能磁盘缓冲区已满且需要处理),则操作系统会提供一个驱动程序可以调用的入口机制,而不是直接执行中断 - 返回自己,(重要的!)。
中断像上面的例子可以使正在等待就绪线程运行和/或可以使运行进入一个等待状态的线程。在处理完中断代码后,操作系统应用其调度算法/ s来确定在中断之前运行的线程集是否与现在应该运行的集相同。如果是,操作系统只是中断返回,如果没有,操作系统必须抢占一个或多个正在运行的线程。如果操作系统需要抢占正在处理中断的CPU内核上运行的线程,则它必须获得对该内核的控制权。它通过“真正的”硬件中断来实现这一点 - 操作系统内部处理器驱动程序设置了一个硬件信号,用于硬件中断运行要被抢占的线程的内核。
当一个线程是被抢占进入OS代码,操作系统可以保存线程的完整上下文。有些寄存器已经通过中断入口保存到线程堆栈中,因此保存线程的堆栈指针将有效地“保存”所有这些寄存器,但操作系统通常需要做更多工作,例如。可能需要刷新高速缓存,可能需要保存FPU状态,并且在要运行的新线程属于与要被抢先的线程不同的进程的情况下,需要将内存管理保护寄存器换出。通常,操作系统尽快从中断线程堆栈切换到专用操作系统堆栈,以避免在每个线程堆栈上造成操作系统堆栈要求。
一旦保存了上下文,操作系统就可以为要运行的新线程“交换”扩展上下文。现在,操作系统可以最终加载新线程的堆栈指针,并执行中断返回以使其新的就绪线程运行。
然后OS不做任何事情。正在运行的线程一直运行,直到出现另一个中断(硬或软)。
要点:
1)OS内核应该被看作是一个大的中断处理程序,它可以决定中断返回一组不同的线程数少于中断的那些的。
2)操作系统可以控制任何进程中的任何线程,并在必要时停止任何线程,而不管它处于什么状态或可能运行什么内核。
3)抢先调度和分派确实会产生在这些论坛上发布的所有同步等问题。最大的好处是在线程级别对硬中断的快速响应。如果没有这些,那么在PC上运行的所有这些高性能应用程序 - 视频流,快速网络等几乎是不可能的。
4)OS定时器只是一组可以改变运行线程集的中断之一。 '时间切片'(呃 - 我讨厌这个词),就绪线程之间只有当计算机超载时才会发生,即。就绪线程集大于可用于运行它们的CPU内核数。如果任何旨在解释操作系统调度的文本在“中断”之前提到“时间片”,它可能会导致比解释更多的混淆。定时器中断只是“特殊的”,因为很多系统调用都有超时时间来备份它们的主要功能(OK,sleep(),超时是主要功能:)。
只是想知道,不是这个等待函数如何在内部工作吗? (显然不包括例外情况。) – Mehrdad 2012-01-12 07:14:52
@ Mehrdad-通常没有。通常这些线程被放置在一个“等待队列”中,而没有给出任何处理器时间。当某些事件发生时会唤醒它们,它们被放回到运行队列中,以便它们被安排。这意味着,如果在任何时候只有两个或三个线程处于活动状态,则可以拥有一百万个睡眠线程,而不会有任何性能损失。 – templatetypedef 2012-01-12 07:16:05
@templatetypedef:那么OS究竟该如何确定线程是否应该在特定的时间片唤醒?它不应该在每个时间片检查循环中线程的状态吗? – Mehrdad 2012-01-12 07:20:52