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

时间:2016-09-04 02:06:00

标签: c# .net visual-studio-2012 process deadlock

我已经读过这个deadlock condition我非常肯定会影响我的代码(下面)。我不明白的是:在过去的12年中,这段代码在Windows Server 2003(.net 2.0)上运行得非常好。现在我们一直在尝试将它移到Windows Server 2012,它总是陷入僵局。

虽然我的DLL是为“anyCPU”构建的(仍然以.net 2.0为目标),但正在运行的可执行进程绝对是32位,而从Server 2003迁移到Server 2012则从32位迁移到64位OS。

我想我知道如何解决这个问题,但是有谁知道为什么这种行为会从Server 2003更改为Server 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);
        }                   
    }           

还有哪些其他情况会导致死锁?如果我要检查StandardError,它会显示任何有用的东西吗?

更新#2:

FWIW,我们已经配置了另一个运行IIS 6的Windows Server 2003(32位)。这是此代码运行12年的原始计算机配置(偶尔会出现死锁)。我们在Server 2012 IIS 8上死锁的相同代码在此Server 2003上没有死锁。

我们现在拥有自己的最小和完整的代码来重现问题。但是,我们已获得该流程执行许可的.exe具有防止我们发布的保密条款。我意识到这对这里的专家没有帮助。

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

由于从admin命令shell或非admin命令shell手动运行的相同命令行参数运行良好,很难相信这是一个64位/ WOW64问题,这个32位可执行文件或它是必需的DLL。我们继续搜索我们的权限可能导致问题的地方(该过程需要写入临时文件夹,我们现在放在c:\ temp)。

1 个答案:

答案 0 :(得分:1)

没有好Minimal, Complete, and Verifiable code example,就不可能完全回答。

我可以告诉你的是,你的代码总是被破坏,并且总是有可能发生死锁。在进程退出之前,您无法从进程中读取任何内容,但如果进程将这么多数据写入stdout缓冲区填充并阻止进程,则进程可能无法退出。

如果你没有重新编译任何东西,但是现在发现你现在看到了死锁,那么最有可能的解释是你开始的过程比以前更多地写入stdout。即之前用于填充缓冲区的所有输出,但现在却没有。 (我想在较新的操作系统中缓冲区大小也有可能降低,但这对我来说似乎不太可能。)

您应该继续将呼叫转移到ReadToEnd()。实际上,你应该完全取消WaitForExit()。如果您正在呼叫ReadToEnd(),那么在该流程实际上已退出之前不会完成,因此之后调用WaitForExit()将毫无意义。