在后台线程运行时的Process.Start()挂(Process.Start() hangs wh

2019-09-01 02:13发布

我已经排查了一整天。 做一些经过研究和大量的试验和错误的,看来我已经能够发出缩小的事实,我调用process.Start()没有一个计时器线程工作。 主线程上运行时,下面的代码工作。 把该完全相同的代码在计时器回调,并且死了。 为什么? 我如何得到它具有定时工作?

private static void RunProcess()
{
    var process = new Process();

    process.StartInfo.FileName = "cmd";
    process.StartInfo.Arguments = "/c exit";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardInput = true;
    process.StartInfo.RedirectStandardOutput = true;

    process.Start();  // code hangs here, when running on background thread

    process.StandardOutput.ReadToEnd();

    process.WaitForExit();
}

编辑

作为测试,我用另一台笔记本电脑这种完全相同的代码,我经历了同样的问题。 这是一个可以粘贴到一个控制台应用程序的完整代码。 process.Start()挂,但只要我按任意键结束, process.Start()程序结束前完成。

private static System.Timers.Timer _timer;
private static readonly object _locker = new object();

static void Main(string[] args)
{
    ProcessTest();

    Console.WriteLine("Press any key to end.");
    Console.ReadKey();
}
private static void ProcessTest()
{
    Initialize();
}
private static void Initialize()
{
    int timerInterval = 2000;
    _timer = new System.Timers.Timer(timerInterval);
    _timer.Elapsed += new ElapsedEventHandler(OnTimerElapsed);
    _timer.Start();
}
private static void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
    if (!Monitor.TryEnter(_locker)) { return; }  // Don't let  multiple threads in here at the same time.
    try
    {
        RunProcess();
    }
    finally
    {
        Monitor.Exit(_locker);
    }
}
private static void RunProcess()
{
    var process = new Process();
    process.StartInfo.FileName = "cmd";
    process.StartInfo.Arguments = "/c exit";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardInput = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.Start();  // ** HANGS HERE **
    process.StandardOutput.ReadToEnd();
    process.WaitForExit();
}

Answer 1:

有很多关于这个问题重复的问题,没有一个恰好适合你的情况。 您可以通过使用调试器的调试+的Windows +线程窗口中看到的问题。 找到计时器线程,然后双击它。 看看调用堆栈窗口中看到:

mscorlib.dll!System.Console.InputEncoding.get() + 0x66 bytes    
System.dll!System.Diagnostics.Process.StartWithCreateProcess(System.Diagnostics.ProcessStartInfo startInfo) + 0x7f5 bytes   
System.dll!System.Diagnostics.Process.Start() + 0x88 bytes  
ConsoleApplication70.exe!Program.RunProcess() Line 43 + 0xa bytes   C#
ConsoleApplication70.exe!Program.OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) Line 28 + 0x5 bytes    C#
    // etc...

该线程死锁在Console.InputEncoding属性的getter。 这是使用Process类找出需要使用编码什么的过程中重定向输出转换成字符串。

这是特定于.NET 4.5,这也将影响到已安装4.5,因为它不是并排端版本.NET的机器上针对4.0的应用程序。 死锁是由你的主线程的Console.ReadKey()方法调用引起的。 现在获取一个锁,以防止其他线程与控制台搞乱。 这一直是整个微软的软件相当全球变化,即在C / C中使用的CRT ++由VS2012创建的应用程序也添加了这个锁。 确切的原因不是很清楚,我,但肯定有做与控制台输出没有得到夹杂着控制台输入,而你的程序要求输入一些东西。 究竟为什么InputEncoding属性需要采取锁定以及,没错,是有点难以解释,但适合顺序访问控制台输入的模式。 当然,这是作为一个巨大的惊喜很多程序员,尤其是编写测试线程代码,像你这样的小测试应用软件的用户。 挫折的位TDD。

解决方法是有点不愉快,TDD明智的,你必须停止使用Console.ReadKey(),以避免死锁。 房地产项目将使用的AutoResetEvent的的WaitOne()方法来知道工作线程执行完毕。 或CountDownEvent.Wait(),更符合尝试代码几次一致。 等等。


UPDATE:此死锁情况在.NET 4.5服务更新就解决了。 你的机器上启动Windows Update来得到它。



文章来源: Process.Start() hangs when running on a background thread