消除 Process.WaitForExit() / StandardOutput 死锁条件
Elimininating Process.WaitForExit() / StandardOutput deadlock condition
我读到过这个 deadlock condition,我很确定这会影响我的代码(如下)。我不明白的是:这段代码在过去的 12 年里 运行ning 在 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,我们已经配置了另一个 Windows Server 2003(32 位),其中 运行s IIS 6。这是原始机器配置此代码 运行 12年(只是偶尔出现僵局)。我们在 Server 2012 IIS 8 上死锁的相同代码在此 Server 2003 上不会死锁。
我们现在拥有自己的最小且完整的代码来重现该问题。但是,我们已授权并由进程执行的 .exe 具有保密条款,阻止我们发布。我意识到这对这里的专家没有帮助。
我们遇到的一个提示是,当 运行 通过安装在实际服务器上的 Visual Studio 2013 调试器时,进程不会 deadlock/hang,同时调用进程从服务器外部的浏览器。奇怪的是 - 从 2012 服务器上的浏览器我们无法连接到该测试页面 - 浏览器只是说 "connecting" 并最终超时(但是,由同一服务器/相同 IIS 8 托管的其他站点可以通过服务器上的浏览器访问!)
由于来自管理命令 shell 或非管理命令 shell 的手动相同命令行参数 运行 工作完美,很难相信它是 64 位的/ WOW64 这个 32 位可执行文件或它是必需的 DLL 有问题。我们继续搜索我们的权限可能导致问题的地方(该过程需要写入一个临时文件夹,我们暂时将其放置在 c:\temp)。
没有好的Minimal, Complete, and Verifiable code example,不可能完全回答。
我可以告诉你的是,你的代码总是有问题,而且总是有死锁的可能。在进程退出之前,您无法从进程中读取任何内容,但是如果进程向 stdout 写入太多数据以至于缓冲区填满并阻塞进程,则进程可能无法退出。
如果您没有重新编译任何东西,但发现您现在看到了以前没有看到的死锁,那么最可能的解释是您正在启动的进程向 stdout 写入的内容比以前多。 IE。以前所有的输出都适合缓冲区,但现在不行了。 (我想也有可能缓冲区大小在较新的 OS 中减少了,但我觉得这不太可能。)
您应该继续将电话转到 ReadToEnd()
。事实上,您应该完全取消 WaitForExit()
。如果您正在调用 ReadToEnd()
,直到进程实际上已经退出,它才会完成,因此之后调用 WaitForExit()
将毫无意义。
我读到过这个 deadlock condition,我很确定这会影响我的代码(如下)。我不明白的是:这段代码在过去的 12 年里 运行ning 在 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,我们已经配置了另一个 Windows Server 2003(32 位),其中 运行s IIS 6。这是原始机器配置此代码 运行 12年(只是偶尔出现僵局)。我们在 Server 2012 IIS 8 上死锁的相同代码在此 Server 2003 上不会死锁。
我们现在拥有自己的最小且完整的代码来重现该问题。但是,我们已授权并由进程执行的 .exe 具有保密条款,阻止我们发布。我意识到这对这里的专家没有帮助。
我们遇到的一个提示是,当 运行 通过安装在实际服务器上的 Visual Studio 2013 调试器时,进程不会 deadlock/hang,同时调用进程从服务器外部的浏览器。奇怪的是 - 从 2012 服务器上的浏览器我们无法连接到该测试页面 - 浏览器只是说 "connecting" 并最终超时(但是,由同一服务器/相同 IIS 8 托管的其他站点可以通过服务器上的浏览器访问!)
由于来自管理命令 shell 或非管理命令 shell 的手动相同命令行参数 运行 工作完美,很难相信它是 64 位的/ WOW64 这个 32 位可执行文件或它是必需的 DLL 有问题。我们继续搜索我们的权限可能导致问题的地方(该过程需要写入一个临时文件夹,我们暂时将其放置在 c:\temp)。
没有好的Minimal, Complete, and Verifiable code example,不可能完全回答。
我可以告诉你的是,你的代码总是有问题,而且总是有死锁的可能。在进程退出之前,您无法从进程中读取任何内容,但是如果进程向 stdout 写入太多数据以至于缓冲区填满并阻塞进程,则进程可能无法退出。
如果您没有重新编译任何东西,但发现您现在看到了以前没有看到的死锁,那么最可能的解释是您正在启动的进程向 stdout 写入的内容比以前多。 IE。以前所有的输出都适合缓冲区,但现在不行了。 (我想也有可能缓冲区大小在较新的 OS 中减少了,但我觉得这不太可能。)
您应该继续将电话转到 ReadToEnd()
。事实上,您应该完全取消 WaitForExit()
。如果您正在调用 ReadToEnd()
,直到进程实际上已经退出,它才会完成,因此之后调用 WaitForExit()
将毫无意义。