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

评论

hurryupandwait.io/blog/detecting-a-hung-windows-process

@ magicandre1981该页面提出了一种方法来检查程序是否正在主动执行某项操作,但这不是Windows实际使用的方法。

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

#1 楼

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

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

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

评论


↑这个。与调度无关,或者与已接受答案中建议的无关,仅与是否定期调用GetMessage(或类似消息)和DispatchMessage有关。

–达蒙
2015年8月24日14:40



接受的答案在正确地引用IsHungAppWindow时会指出,处于启动阶段的程序不必调用GetMessage。

– MSalters
15年8月25日在9:56

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

–棘轮怪胎
15年8月25日在11:54

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

– MSalters
15年8月25日在12:27

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

–戴夫·库西诺(Dave Cousineau)
15年8月26日在22:33

#2 楼

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

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

有一个SDK Windows函数IsHungAppWindow


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


源IsHungAppWindow函数


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


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


它是否一直不断轮询所有正在运行的应用程序?没有轮询应用程序,但给定了处理器时间。

Windows有一个调度系统,可以为应用程序线程分配处理器时间。

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

评论


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

–usr
15年8月24日在10:52

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

–DavidPostill♦
15年8月24日在10:54

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

–DavidPostill♦
2015年8月24日10:59



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

–罗安
15年8月24日在11:56

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

–安迪
15年8月25日在22:01

#3 楼

实际上,Windows并不总是知道应用程序没有响应。该应用程序必须是具有窗口的交互式应用程序,并且该窗口必须接收该应用程序无法处理的消息,然后Windows才能确定该应用程序没有响应。

例如,Windows没有一种知道没有从命令行运行的没有用户界面的数字处理应用程序是否正在执行它的工作,或者可能陷入无限循环的方式。

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

应用程序可能会以Windows无法识别的方式挂起。例如,应用程序可能会继续轮询其消息队列中的消息而没有对其进行适当的操作,因此,出于所有实际意图和目的,该应用程序将显示为“挂起”,而Windows不会意识到它没有响应。

评论


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

–安迪
2015年8月25日在22:05



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

– BlueRaja-Danny Pflughoeft
15年8月25日在23:50

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

–维克多·托特(Viktor Toth)
15年8月26日在3:29

#4 楼

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

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

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

#5 楼

问题的答案是是/否。

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

真正的答案

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

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

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

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

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

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