消除Process.WaitForExit() / StandardOutput死锁条件

本文关键字:StandardOutput 死锁 条件 Process WaitForExit 消除 | 更新日期: 2023-09-27 18:05:37

我读过关于这个死锁条件的文章,我很确定它影响了我的代码(如下)。我不明白的是:在过去的12年里,这段代码在Windows Server 2003 (.net 2.0)上运行得非常好。现在我们一直在尝试将它转移到Windows Server 2012,在那里它总是死锁。

虽然我的dll是为"anyCPU"构建的(仍然针对。net 2.0),但正在运行的可执行进程绝对是32位的,从Server 2003到Server 2012的移动是从32位到64位的操作系统。

我想我明白该怎么做来解决这个问题,但是有没有人知道为什么这种行为会从服务器2003改变到服务器2012?

public string DoMyProcess(string filenameAndPath, string arguments)
{
    string stdout="";
    int exitCode = 0;               
    try 
    {               
        ProcessStartInfo procStartInfo = new ProcessStartInfo();
        procStartInfo.FileName = filenameAndPath;
        procStartInfo.CreateNoWindow = true;
        procStartInfo.Arguments = arguments;            
        procStartInfo.RedirectStandardOutput = true;
        procStartInfo.UseShellExecute = false;
        System.Diagnostics.Process theProcess = null;
        try
        {
            theProcess = Process.Start(procStartInfo);
            theProcess.WaitForExit();
            exitCode = theProcess.ExitCode;
            // moving this ABOVE WaitForExit should eliminate deadlocks
            // But why did it always work on Server 2003 but not on Server 2012?
            stdout = theProcess.StandardOutput.ReadToEnd();
        }
        catch (System.Exception e)
        {
            string errMsg = e.Message;
            log_the_error("threw an exception: " + e.Message);
        }                   
    }           
    return stdout;
}
更新:

神秘死锁仍然存在,即使按照建议修改了上述代码:

        try
        {
            theProcess = Process.Start(procStartInfo);
            stdout = theProcess.StandardOutput.ReadToEnd();                     
        }
        catch (System.Exception e)
        {
            string errMsg = e.Message;
            log_the_error("threw an exception: " + e.Message);
        }                   
    }           

还有哪些条件会导致死锁?如果我要检查standardror,它会揭示一些有用的东西吗?

更新# 2:

顺便说一下,我们已经配置了另一个运行IIS 6的Windows Server 2003(32位)。这是这段代码运行了12年的原始机器配置(只有偶尔出现死锁)。我们在Server 2012上的死锁代码在Server 2003上不会死锁。

我们现在有了自己的最小和完整的代码来重现这个问题。但是,我们授权的进程正在执行的。exe有保密条款,阻止我们发布。我意识到这对这里的专家没有帮助。

我们遇到的一个提示是,当通过安装在实际服务器上的Visual Studio 2013调试器运行时,进程不会死锁/挂起,而从服务器外部的浏览器调用该进程。奇怪的是,从2012服务器上的浏览器我们无法连接到该测试页面-浏览器只是说"连接"并最终超时(然而,由同一服务器/同一IIS 8托管的其他站点可以从服务器上的浏览器访问!)

由于在管理命令shell或非管理命令shell中手动运行相同的命令行参数都可以完美地工作,因此很难相信这是这个32位可执行文件的64位/WOW64问题,或者它需要dll。我们继续搜索我们的权限可能导致问题的位置(该进程需要写入临时文件夹,目前我们将其放置在c:'temp)。

消除Process.WaitForExit() / StandardOutput死锁条件

如果没有一个好的最小化、完整和可验证的代码示例,就不可能完全回答这个问题。

我可以告诉你的是,你的代码总是被破坏,并且总是有死锁的可能。在进程退出之前,您无法从进程中读取任何内容,但是如果进程向标准输出写入的数据太多,缓冲区填充并阻塞了进程,则进程可能无法退出。

如果您没有重新编译任何东西,但是发现现在看到了死锁,那么最可能的解释是您正在启动的进程比以前更多地写入标准输出。也就是说,以前所有的输出都适合缓冲区,但现在不行了。(我猜也有可能在较新的操作系统中减少了缓冲区大小,但对我来说似乎不太可能。)

您应该继续并将呼叫移动到ReadToEnd()。事实上,你应该完全放弃WaitForExit()。如果您正在调用ReadToEnd(),那将不会完成,直到进程实际上已经退出,所以调用WaitForExit()之后将毫无意义。