简体   繁体   English

System.Diagnostics.Process.Start奇怪的行为

[英]System.Diagnostics.Process.Start weird behaviour

I'm writing an application to start and monitor other applications in C#. 我正在编写一个应用程序来启动和监视C#中的其他应用程序。 I'm using the System.Diagnostics.Process class to start applications and then monitor the applications using the Process.Responding property to poll the state of the application every 100 milisecs. 我正在使用System.Diagnostics.Process类来启动应用程序,然后使用Process.Responding属性监视应用程序,以每100毫秒轮询一次应用程序的状态。 I use Process.CloseMainWindow to stop the application or Process.Kill to kill it if it's not responding. 我使用Process.CloseMainWindow来停止应用程序或Process.Kill如果它没有响应就杀死它。

I've noticed a weird behaviour where sometimes the process object gets into a state where the responding property always returns true even when the underlying process hangs in a loop and where it doesn't respond to CloseMainWindow. 我注意到一种奇怪的行为,有时进程对象进入一种状态,即当底层进程在循环中挂起并且它不响应CloseMainWindow时,响应属性总是返回true。

One way to reproduce it is to poll the Responding property right after starting the process instance. 重现它的一种方法是在启动流程实例后立即轮询Responding属性。 So for example 所以举个例子

_process.Start();
bool responding = _process.Responding;

will reproduce the error state while 将重现错误状态

_process.Start();
Thread.Sleep(1000);
bool responding = _process.Responding;

will work. 将工作。 Reducing the sleep period to 500 will introduce the error state again. 将睡眠周期减少到500将再次引入错误状态。

Something in calling _process.Responding too fast after starting seems to prevent the object from getting the right windows message queue handler. 启动后调用_process.Responding太快的东西似乎阻止了对象获取正确的Windows消息队列处理程序。 I guess I need to wait for _process.Start to finish doing it's asynchronous work. 我想我需要等待_process.Start完成它的异步工作。 Is there a better way to wait for this than calling Thread.Sleep ? 有没有比调用Thread.Sleep更好的方法来等待这个? I'm not too confident that the 1000 ms will always be enough. 我不太自信1000毫秒总是足够的。

Now, I need to check this out later, but I am sure there is a method that tells the thread to wait until it is ready for input. 现在,我需要稍后检查一下,但我确信有一个方法告诉线程等待它准备输入。 Are you monitoring GUI processes only? 您是否仅监控GUI流程?

Isn't Process.WaitForInputIdle of any help to you? 是不是Process.WaitForInputIdle对你有任何帮助? Or am I missing the point? 或者我错过了这一点? :) :)

Update 更新

Following a chit-chat on Twitter (or tweet-tweet?) with Mendelt I thought I should update my answer so the community is fully aware.. 在Twitter(或推文推文?)与门德尔聊天之后,我想我应该更新我的答案,以便社区充分了解...

  • WaitForInputIdle will only work on applications that have a GUI. WaitForInputIdle仅适用于具有GUI的应用程序。
  • You specify the time to wait, and the method returns a bool if the process reaches an idle state within that time frame, you can obviously use this to loop if required, or handle as appropriate. 您指定等待的时间,如果进程在该时间范围内达到空闲状态,则该方法返回bool,显然,如果需要,您可以使用它循环,或者根据需要进行处理。

Hope that helps :) 希望有帮助:)

I think it may be better to enhance the check for _process.Responding so that you only try to stop/kill the process if the Responding property returns false for more than 5 seconds (for example). 我认为增强对_process.Responding的检查可能会更好,这样如果Responding属性返回false超过5秒(例如),你只会尝试停止/终止进程。

I think you may find that quite often, applications may be "not responding" for a split second whilst they are doing more intensive processing. 我想你可能会发现,在他们进行更密集的处理时,应用程序可能会在一瞬间“没有响应”。

I believe a more lenient approach will work better, allowing a process to be "not responding" for a short amount of time, only taking action if it is repeatedly "not responding" for several seconds (or however long you want). 我相信一种更宽松的方法会更好地工作,允许一个过程在短时间内“没有响应”,只有在几秒钟内(或者你想要多长时间)反复“没有响应”时才采取行动。

Further note: The Microsoft documentation indicates that the Responding property specifically relates to the user interface, which is why a newly started process may not have it's UI responding immediately. 进一步说明:Microsoft文档表明Responding属性与用户界面特别相关,这就是新启动的进程可能没有立即响应UI的原因。

Thanks for the answers. 谢谢你的回答。 This 这个

_process.Start();
_process.WaitForInputIdle();

Seems to solve the problem. 似乎解决了这个问题。 It's still strange because Responding and WaitForInputIdle should both be using the same win32 api call under the covers. 它仍然很奇怪,因为Responding和WaitForInputIdle都应该使用相同的win32 api调用。

Some more background info 更多背景信息
GUI applications have a main window with a message queue. GUI应用程序有一个带有消息队列的主窗口。 Responding and WaitForInputIdle work by checking if the process still processes messages from this message queue. Responding和WaitForInputIdle通过检查进程是否仍处理来自此消息队列的消息来工作。 This is why they only work with GUI apps. 这就是他们只使用GUI应用程序的原因。 Somehow it seems that calling Responding too fast interferes with getting the Process getting a handle to that message queue. 不知怎的,似乎调用Responding太快会干扰让Process获取该消息队列的句柄。 Calling WaitForInputIdle seems to solve that problem. 调用WaitForInputIdle似乎解决了这个问题。

I'll have to dive into reflector to see if I can make sense of this. 我将不得不潜入反射器,看看我是否能理解这一点。

update 更新
It seems that retrieving the window handle associated with the process just after starting is enough to trigger the weird behaviour. 似乎在启动后检索与进程关联的窗口句柄足以触发奇怪的行为。 Like this: 像这样:

_process.Start();
IntPtr mainWindow = _process.MainWindowHandle;

I checked with Reflector and this is what Responding does under the covers. 我使用Reflector进行了检查,这就是Responding在幕后所做的事情。 It seems that if you get the MainWindowHandle too soon you get the wrong one and it uses this wrong handle it for the rest of the lifetime of the process or until you call Refresh(); 似乎如果你太快得到MainWindowHandle,你会得到错误的一个,并且它会在进程的剩余生命周期中使用这个错误的句柄,或者直到你调用Refresh();

update 更新
Calling WaitForInputIdle() only solves the problem some of the time. 调用WaitForInputIdle()只能在某些时候解决问题。 Calling Refresh() everytime you read the Responding property seems to work better. 每次读取Responding属性时调用Refresh()似乎都会更好。

I too noticed that in a project about 2 years ago. 我在大约两年前的一个项目中也注意到了这一点。 I called .Refresh() before requesting certain prop values. 在请求某些道具值之前,我调用了.Refresh()。 IT was a trial-and-error approach to find when I needed to call .Refresh(). 当我需要调用.Refresh()时,IT是一种试错法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM