我看到一个关于为什么“轮询不好”的问题。就最小化一个线程使用的处理器时间而言,最好进行自旋等待(即,在 while 循环中轮询所需的更改)或等待内核对象(例如Windows 中的内核事件对象)?

对于上下文,假设代码需要在任何类型的处理器(单核、超线程、多核等)上运行。还假设要轮询或等待的线程如果进行轮询而不是等待,则在轮询结果令人满意之前无法继续。最后,线程开始等待(或轮询)与满足条件之间的时间可能会从很短的时间到很长的时间不等。

由于操作系统在“等待”的情况下可能会更有效地“轮询”,所以我不想看到“等待只是意味着其他人进行轮询”的说法,这是旧消息,并且不一定 100% 准确。

有帮助吗?

解决方案

倘若OS具有这些类型并发原语的合理实施方式中,这绝对是最好等待内核对象上。

除了其它原因,这让OS不知道来调度所涉及的线程为额外的时间片,直到被等待换的对象是在适当的状态。否则,必须被经常收到重新调度一个线程,上下文切换到的,然后在一段时间运行。

您具体询问最小化处理器时间用于一个线程:该线程阻塞内核对象上会使用ZERO时在这个例子中;轮询线程将使用的时间各种

此外,“别人是轮询”的说法不一定是真实的。当一个内核对象进入相应状态,内核可以看看,看看在那个瞬间哪些线程正在等待该对象...,然后安排一个或更多的人来执行。没有必要为内核(或其他人)轮询在这种情况下,任何东西。

其他提示

等待是“更好”的方式来表现。当你在一个内核对象的等待你的线程将不会被授予,因为它是由调度没有工作准备已知的任何CPU时间。您的线索,只是要给予CPU时间时,它的等待条件被满足。这意味着你将不会被不必要地占用CPU资源。

我觉得还没有被提出的一个问题是,如果你的操作系统有很多工作要做,阻断yeilds你的线程到另一个进程。如果所有进程使用阻塞原语,他们应该(如内核等待,文件/网络IO等),你给内核更多的信息来选择哪个线程应该运行。因此,它会在相同的时间内做更多的工作。如果您的应用程序可以做一些有用的事情,同时等待该文件打开或到达的数据包,然后将yeilding甚至能帮助你自己的应用程序。

等待确实涉及更多的资源以及用于附加的上下文切换。事实上,一些同步原语等CLR监视器和Win32临界区使用两阶段锁定协议 - 一些自旋等待完成前实际上做一个真正的等待

我想象做了两阶段的事情将是非常困难的,而且会涉及大量的测试和研究。所以,除非你有足够的时间和资源,坚持走窗户元......他们已经做了研究你。

有只有几个地方,通常在操作系统的低层次的东西(中断处理程序/设备驱动器),其中自旋等待有意义需要/。一般用途的应用总是最好等待互斥像/条件变量/信号灯一些同步原语。

我同意Darksquid,如果你的操作系统有不俗的并发原语,那么你不应该需要轮询。轮询通常是到它自己的实时系统或限制硬件不具有操作系统,那么你需要轮询,因为你可能没有选择等待(),而且还因为它可以让你finegrain控制究竟有多长要在一个特定的状态,以等待,而不是作为在调度的摆布。

等待(阻塞)几乎总是最好的选择(“最佳”是指有效利用处理资源并最大限度地减少对同一系统上运行的其他代码的影响)。主要的例外情况是:

  1. 当预期轮询持续时间很小时(与阻塞系统调用的成本类似)。
  2. 大多数情况下在嵌入式系统中,当 CPU 专门用于执行特定任务并且让 CPU 空闲时没有任何好处(例如,90 年代末构建的一些软件路由器就使用了这种方法。)

轮询通常不会在操作系统内核中用于实现阻塞系统调用 - 相反,事件(中断、计时器、互斥体上的操作)会导致阻塞的进程或线程变得可运行。

人们可以采取四种基本方法:

  1. 使用一些操作系统等待原语来等待事件发生
  2. 使用一些操作系统定时器原语以某种定义的速率检查事件是否已经发生
  3. 反复检查事件是否已发生,但在事件未发生时使用操作系统原语生成任意且未知持续时间的时间片。
  4. 反复检查事件是否发生,如果没有发生则不释放CPU。

当#1 可行时,它通常是最好的方法,除非延迟对事件的响应可能是有益的。例如,如果预计在几秒钟内接收大量串行端口数据,并且在发送数据后 100ms 处理数据与立即处理数据一样好,则使用后两者之一进行定期轮询方法可能比设置“收到数据”事件更好。

方法#3 相当粗糙,但在许多情况下可能是一个好的方法。与方法 1 相比,它通常会浪费更多的 CPU 时间和资源,但在许多情况下,它会更容易实现,并且资源浪费在许多情况下足够小,无关紧要。

方法 #2 通常比方法 #3 更复杂,但具有能够使用单个计时器处理许多资源且无需专用线程的优点。

方法 #4 有时在嵌入式系统中是必要的,但通常非常糟糕,除非直接轮询硬件,并且在相关事件发生之前不会做任何有用的事情。在许多情况下,在等待条件的线程释放 CPU 之前,等待条件不可能发生。实际上,如方法 #3 中那样让出 CPU 将允许等待线程比占用事件更快地看到事件。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top