Windows如何知道程序是否没有响应?


174

Windows如何知道程序是否没有响应?它会不断轮询所有正在运行的应用程序吗?



@ magicandre1981该页面提出了一种方法来检查程序是否正在做某事,但这不是Windows实际使用的方法。
凯文·潘科

看一下Windows消息队列,候选对象是PeekMessage()函数
Luciano

Answers:


150

应用程序从Windows提供的队列中获取事件。

如果应用程序在一段时间(5秒)内没有轮询事件队列(例如进行长时间计算时),则Windows会假定该应用程序已挂起并向用户发出警报。

为了避免这种情况,应用程序应该将昂贵的计算推送到工作线程或拆分处理,并确保定期轮询队列。


27
↑这个。与安排时间或接受的答案中建议的内容无关,仅取决于您是否定期致电GetMessage(或类似电话)和DispatchMessage
戴蒙2015年

1
IsHungAppWindow正确回答所接受的答案表示在启动阶段的程序不必调用GetMessage
MSalters

@MSalters将启动定义为第一次启动之前的时间GetMessage?该功能允许简单的命令行应用程序正常工作而不会被挂起,因为它们不需要轮询队列。
棘轮怪胎

4
@ratchetfreak:大概在第一个CreateWindow调用之前。命令行应用程序完全是不同的野兽。它们在ConHost.EXE中运行,并且与Windows GUI susbystem交互。
MSalters

1
同样,在我看来,在Windows 7(可能更早)中,如果您尝试以某种方式操作窗口失败,则窗口会更快地注意到这一点。例如,如果程序不处理最大化或移动消息,则Windows 7会在大约1或2秒后立即跳转为不响应
。–

78

Windows如何知道程序是否没有响应?

如果没有Windows的源代码,我们将无法确定其内部在做什么。

有一个IsHungAppWindow可以使用的Windows SDK功能。

如果应用程序未等待输入,未处于启动处理中且未在5秒钟的内部超时时间内调用PeekMessage,则认为该应用程序没有响应。

IsHungAppWindow函数

如果顶级窗口停止响应消息超过几秒钟,则系统认为该窗口没有响应。在这种情况下,系统将隐藏窗口并将其替换为具有相同Z顺序,位置,大小和视觉属性的重影窗口。这使用户可以移动它,调整大小,甚至关闭应用程序。但是,这些是唯一可用的操作,因为应用程序实际上没有响应。

关于消息和消息队列的来源


它会不断轮询所有正在运行的应用程序吗?

不会。不对应用程序进行轮询,但会给定处理器时间。

Windows有一个调度系统,该调度系统使处理器有时间处理应用程序线程。

调度算法很复杂,并且在Windows Internals,第1部分(第6版)(开发人员参考)中有完整描述。


2
挂起状态不是基于CPU。在这种情况下,大多数程序在99.999%的时间内都是“挂起”的,什么也不做。
usr

2
@usr在哪里说“挂”取决于CPU?
DavidPostill

2
@usr答案的前半部分回答“它是否一直不断轮询所有正在运行的应用程序?”。下半部分回答“ Windows如何知道程序是否未响应?
。OP一举

9
但是,这不是真正的轮询吗?我认为内部结构更像是在您调用时在窗口上发出等待句柄的信号PeekMessage。因此,当Windows向应用程序发送消息且五秒钟内未收到信号时,它将应用程序标记为未响应。实际上,在较新的Windows上,如果该窗口未能及时响应用户输入,则该窗口仅被标记为“不响应” -直到我尝试单击或按下某个键或其他操作时,应用程序才能轻松地保持“挂起”状态。分钟内没有“出现”无响应。
罗安2015年

2
您可以删除“关于消息和消息队列”上方的所有内容,因为它无济于事。Windows知道某个应用程序已停止响应,因为它停止了发送消息。该应用程序可能正在运行,因为它会做一些密集的工作,而不是发送消息(但这就是设计不良的程序)。
安迪

32

实际上,Windows并不总是知道应用程序没有响应。该应用程序必须是带有窗口的交互式应用程序,并且在Windows得出该应用程序没有响应之前,该窗口必须正在接收该应用程序无法处理的消息。

例如,Windows无法知道是否有没有通过命令行运行的没有用户界面的数字运算应用正在执行它的工作,或者陷入了无限循环。

Windows中的交互式图形应用程序通过连续轮询消息队列来接收事件。Windows使用键盘,鼠标,计时器等事件填充此消息队列。如果某个应用程序在一段时间内无法轮询消息队列(5秒钟是IsHungAppWindow()函数文档中提到的超时),则Windows认为该应用程序“挂起”,可以通过更改窗口标题(添加文本“ (无响应)”或本地化版本中的等效文本),如果用户尝试与窗口互动,则将窗口内容显示为灰色。

应用程序可能会以Windows无法识别的方式挂起。例如,一个应用程序可能会继续轮询其消息队列中的消息,而没有对其进行适当的处​​理,因此,出于所有实际意图和目的,如果Windows不认识到它是无响应的,则它似乎“挂起”。


8
根据定义,不响应意味着不处理窗口消息,因此它不适用于服务或控制台应用程序,因此我想说Windows总是知道应用程序是否没有响应。您混淆了死锁并且没有响应。
安迪

当然,它可以知道程序是否没有响应。“不响应”与“陷入无限循环”不同
BlueRaja-Danny Pflughoeft

1
实际上,应用程序可以通过GetMessage()检索消息并无法对其进行处理,并且Windows不会将其识别为对用户没有响应的事实,因此Windows不会将其识别为“未响应”。术语“不响应”通常也用于描述网络,服务,交互式命令行等应用程序;AFAIK没有正式的定义将短语限制为窗口应用程序。死锁或无限循环(或任何其他编程错误)都可能导致应用程序变得无响应,但是不,我没有混淆因果关系。
维克多·托特

10

Windows是一个操作系统,它负责监视所有正在运行的程序。

Windows使用事件与基于窗口的应用程序进行通信。每个程序都有一个线程,该线程不断侦听传入的事件并对其进行处理。例如,当您单击按钮或通知区域图标时,Windows会生成一个事件并将其提供给适当的过程。然后,该过程可以决定如何处理它。

在Windows中,与程序的所有交互都是基于事件的,因此当程序长时间不处理传入事件时,表示它不会响应。正如@DavidPostill在其答案中发现并指出的,超时时间为5秒。PeekMessage是从事件队列获取事件的函数。


0

您问题的答案是是/否。

尽管Windows操作系统可以并且确实通过Windows消息队列中的事件来轮询应用程序,但程序绝对没有义务链接到WinAPI或处理/应答Windows队列。即使回答队列中的消息,也不会告诉Windows程序是否已“锁定”。这是一个指标,但仅此而已。真正的答案要复杂得多。

真正的答案

人们在这里避开实际答案。确定程序是否“无响应”是“ 停止问题 ”的一种变体,这在计算机科学中是无法确定的。简短的解释是,处理器不能充当第三方来观察自己,以确定子例程是否陷入无限循环,什么也不做,而是增加一个将以某个固定的正常数字终止的计数器。这两个都可以认为是紧密闭环的。一个停止,另一个永不终止。甚至您作为一个人,也不知道程序是否实际上在响应,特别是如果它处于紧密闭合的循环中时,您仅知道它是否应该(响应)。

从Windows的角度来看,这两个循环都是“无响应”的。这就是Windows让您选择等待还是终止的原因,因为它无法显示。

因此推论是“为什么Windows知道进程正在响应?” 答案很聪明。在多线程和多进程OS中编译某个进程时,有时甚至在紧密闭环的情况下,编译器可能会添加yield()命令,该命令向处理器提供方便的通知,告知它可以切换到其他正在运行的进程。它“放弃”处理器,然后发生“上下文切换”(称为),使操作系统(包括Windows)能够响应堆栈中的其他事件,其中一些事件包括跟踪进程响应。

**这并不意味着响应过程将终止。**无限循环内的进程可以产生处理器,从而允许Windows处理其他事件。

在某些Windows程序中,该程序将处理Windows操作系统信号,该信号可以告诉操作系统“正在响应”,但没有任何程序有义务这样做。您甚至可以在Windows的高级语言(例如perl,php,python和Windows)中编写非常简单的CPU占用率,非终止程序,而Windows可能无法检测到它没有终止且没有响应。那时,Windows取决于试探法-CPU负载,内存,在程序“猜测”期间处理器处理的中断次数。再次,此时,Windows必须要求您终止,因为它确实不知道是否应该终止。

另请参阅Viktor的(正确)答案。忽略有关“不响应”是否与无限循环不同的注释。在不通知Windows消息队列的情况下,应用程序可能会或可能不会处理各种消息,中断,循环。处理消息队列只是OS保持计数以尝试猜测进程是否已挂起的多种事件之一。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.