Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 进程。已退出竞争条件_C#_Process_Synchronization_Race Condition - Fatal编程技术网

C# 进程。已退出竞争条件

C# 进程。已退出竞争条件,c#,process,synchronization,race-condition,C#,Process,Synchronization,Race Condition,我有一个System.Diagnostics.Process的实例,它是通过Process.getProcessByName创建的 成功打开进程后,我执行各种操作,例如读取其内存和窗口标题 这些操作是基于计时器不断执行的,我的意思是计时器。经过的事件处理程序是流程操作的源 现在,我注意到我有一个种族问题,我无法用我所知道的任何东西来解决。下面是它是如何发生的: timerElapsedEvent(...) { if (!process.HasExited) { pro

我有一个
System.Diagnostics.Process
的实例,它是通过
Process.getProcessByName
创建的

成功打开进程后,我执行各种操作,例如读取其内存和窗口标题

这些操作是基于计时器不断执行的,我的意思是
计时器。经过的
事件处理程序是流程操作的源

现在,我注意到我有一个种族问题,我无法用我所知道的任何东西来解决。下面是它是如何发生的:

timerElapsedEvent(...) {

    if (!process.HasExited) {

        process.Refresh(); // Update title.
        var title = process.MainWindowTitle;
    }

}
如果进程正在运行,并且我的代码进入
If
块,则在执行
process.MainWindowTitle
调用之前,进程很可能退出,这将导致异常

我需要的是一种方法,以某种方式捕获进程的退出事件并使其保持活动状态,直到安全地关闭它,而不会使监视它的应用程序崩溃,从而确保它在关闭前等待
进程。MainWindowTitle
(或解决此问题的任何其他解决方案)

此外,同时,另一个方法可能正在运行
ReadProcessMemory
,这也会崩溃

我怎样才能解决这个问题

PS:Process.Exit事件处理程序不工作,因为它不会在
Process.MainWindowTitle
之前被激发,它只会在当前指令完成后被激发。 我非常确定,以某种方式控制退出事件是解决这个问题的唯一方法,因为HasExit可以随时更改,而不取决于我在实际调用流程方法之前进行了多少检查


PS2:我刚刚意识到这是一个托托案件,除非我能控制我打开的过程,否则无法解决,所以我把这个留在这里,只是想看看是否有人知道如何解决这个问题。

简短版本:你不能

这里有一个基本的“检查时间到使用时间”问题,您没有足够的控制来解决。在您检查
HasExited
属性和检查
MainWindowTitle
属性之间,操作系统始终能够终止您正在处理的进程(任意终止,或由于进程中的某些故障终止)

进程
类在强制获取异常方面做得不多,但它做得足够了。特别是,调用
Refresh()
会强制类“忘记”它所知道的有关进程的任何信息,以便在您再次请求时它将重新检索信息。这包括进程的主窗口句柄

进程
类使用本机窗口枚举函数来搜索已知进程ID的窗口句柄。由于进程已退出,它找不到句柄,返回一个
NULL
值(
IntPtr.Zero
)。看到null返回值时,
进程
类强制调用
InvalidOperationException


唯一可靠的解决方案是始终做好捕获异常的准备。在检查状态和尝试做依赖于状态的事情之间,总是有机会改变状态


虽然是学术性的,但我发现有趣的是,如果设置
EnableRaisingEvents
属性,那么
进程
类在检测已退出的进程和抛出异常方面可以(通常是)更有效

特别是,当设置了
EnableRaisingEvents
属性时,
进程
类将在进程句柄发出信号时(通过线程池的
RegisterWaitForSingleObject()
方法)由操作系统通知。也就是说,在这种情况下,
进程
类甚至不需要搜索主窗口句柄,因为如果进程退出,它几乎会立即得到通知

(当然,在一个非常小的机会窗口中,仍然存在潜在的内部竞争条件,因为当
进程
类检查has exited状态时,通知可能尚未到达,但在
进程
类枚举窗口之前,该进程可能仍已退出)


无论如何,这最后一点并不影响基本答案;这只是我在漫游时学到的一点琐事,发现很有趣。:)

简单地捕获
InvalidOperationException
并将其视为已退出的进程有什么不对?在处理外部过程时,存在各种根本无法解决的竞争条件;你的代码只需要准备好处理可能发生的错误。嘿,彼得!捕获异常没有什么问题,我只是想确保没有办法同步线程或其他什么,没有解决方案。无论你做什么(在合理范围内…如果你准备好了根工具包系统并接管Windows内核,我想你可以做你想做的任何事情:),进程可能会被终止,而不可能与之同步。正如您必须随时准备捕获
FileNotFoundException
一样,即使您刚刚看到
File.Exists()
return
true
,即使
进程.HasExited
属性刚刚返回
true
,您自己的代码也需要始终为进程退出做好准备。我完全同意您的推理。虽然Process.HasExited会返回false,但不是true。我不认为这是线程问题。一定是本机调用失败了(或者我在处理这个问题的托管代码中遗漏了一些东西,尽管我很确定我没有)。我做了一个快速测试,并确认即使未设置
EnableRaisingEvents
时也会发生异常
true
。所以,是的,你必须去旅行,除了做好准备,你真的无能为力