2010-12-15 24 views
6

我在將控制檯輸出重定向到Windows窗體文本框時遇到問題。問題是線程相關的。我以下列方式運行的控制檯應用程序,如何以線程安全的方式將控制檯程序的輸出重定向到文本框?

private void RunConsoleApp() 
{ 
    Process proc = new Process(); 
    proc.StartInfo.FileName = "app.exe"; 
    proc.StartInfo.Arguments = "-a -b -c"; 
    proc.StartInfo.UseShellExecute = false; 

    // set up output redirection 
    proc.StartInfo.RedirectStandardOutput = true; 
    proc.StartInfo.RedirectStandardError = true;  
    proc.EnableRaisingEvents = true; 
    proc.StartInfo.CreateNoWindow = true; 

    // Set the data received handlers 
    proc.ErrorDataReceived += proc_DataReceived; 
    proc.OutputDataReceived += proc_DataReceived; 

    proc.Start(); 
    proc.BeginErrorReadLine(); 
    proc.BeginOutputReadLine(); 
    proc.WaitForExit(); 

    if (proc.ExitCode == 0) 
    { 
     out_txtbx.AppendText("Success." + Environment.NewLine); 
    } 
    else 
    { 
     out_txtbx.AppendText("Failed." + Environment.NewLine); 
    } 
} 

,然後捕獲並與該輸出處理器處理數據,

// Handle the date received by the console process 
void proc_DataReceived(object sender, DataReceivedEventArgs e) 
{ 
    if (e.Data != null) 
    { 
     if ((e.Data.EndsWith("DONE.")) || (e.Data.EndsWith("FAILED.")) || 
      (e.Data.StartsWith("RESET"))) 
     { 
      // This crashes the application, but is supposedly the correct method 
      this.AppendText(e.Data + Environment.NewLine); 

      // This works, but the debugger keeps warning me that the call 
      // is not thread safe 
      //out_txtbx.AppendText(e.Data + Environment.NewLine); 
     } 
    } 
} 

控制檯文本然後將其附加這樣,

delegate void AppendTextDelegate(string text); 

// Thread-safe method of appending text to the console box 
private void AppendText(string text) 
{ 
    // Use a delegate if called from a different thread, 
    // else just append the text directly 
    if (this.out_txtbx.InvokeRequired) 
    { 
     // Application crashes when this line is executed 
     out_txtbx.Invoke(new AppendTextDelegate(this.AppendText), new object[] { text }); 
    } 
    else 
    { 
     this.out_txtbx.AppendText(text); 
    } 
} 

從所有文檔和示例中我看到這看起來是正確的方法,只是它調用out_txtbx.Invoke時會崩潰應用程序。

什麼可以打破,有什麼替代方法可以做到這一點?


(如由Hans帕桑特指出)

的問題是,應用程序被陷在「死鎖」爲線的結果,

proc.WaitForExit(); 

該行應刪除,方法應該看起來像這樣,

private void RunConsoleApp() 
{ 
    Process proc = new Process(); 
    proc.StartInfo.FileName = "app.exe"; 
    proc.StartInfo.Arguments = "-a -b -c"; 
    proc.StartInfo.UseShellExecute = false; 

    // set up output redirection 
    proc.StartInfo.RedirectStandardOutput = true; 
    proc.StartInfo.RedirectStandardError = true;  
    proc.EnableRaisingEvents = true; 
    proc.StartInfo.CreateNoWindow = true; 

    // Set the data received handlers 
    proc.ErrorDataReceived += proc_DataReceived; 
    proc.OutputDataReceived += proc_DataReceived; 

    // Configure the process exited event 
    proc.Exited += new EventHandler(ProcExited); 

    proc.Start(); 
    proc.BeginErrorReadLine(); 
    proc.BeginOutputReadLine(); 

    // This blocks the main thread and results in "deadly embrace" 
    // The Process.Exited event should be used to avoid this. 
    //proc.WaitForExit(); 
} 

和應提供的事件處理程序,

/// <summary> 
/// Actions to take when console process completes 
/// </summary> 
private void ProcExited(object sender, System.EventArgs e) 
{ 
    Process proc = (Process)sender; 

    // Wait a short while to allow all console output to be processed and appended 
    // before appending the success/fail message. 
    Thread.Sleep(40); 

    if (proc.ExitCode == 0) 
    { 
     this.AppendText("Success." + Environment.NewLine); 
     ExitBootloader(); 
    } 
    else 
    { 
     this.AppendText("Failed." + Environment.NewLine); 
    } 

    proc.Close(); 
} 
+2

你會得到什麼錯誤? – SLaks 2010-12-15 18:37:14

+0

而且在哪一行? – decyclone 2010-12-15 18:46:04

+0

我已經完成了這個沒有錯誤。如果在我可以訪問我的代碼示例時沒有足夠的答案,我會發布。請注意,這將在今晚晚些時候回家。我創建了寫入文本框的TextWriter對象,然後將Console.SetOut指向TextWriter。請參閱http://msdn.microsoft.com/en-us/library/system.console.setout%28v=VS.90%29.aspx – IAbstract 2010-12-15 18:47:48

回答

9
proc.WaitForExit(); 

它被稱爲死鎖。您的主線程被阻塞,等待進程退出。這阻止了它履行基本義務。像保持UI更新一樣。並確保分派Control.Invoke()請求。這阻止了AppendText()方法的完成。這阻止了退出的過程。這會阻止你的UI線程通過WaitForExit()調用。 「致命的擁抱」,又名僵局。

你不能阻止你的主線程。改用Process.Exited事件。

+0

感謝漢斯,這是非常有意義的(現在你已經解釋了它)。 – 2010-12-15 20:31:37

0

嘗試

out_txtbx.Invoke(new AppendTextDelegate(this.AppendText), text); 
+1

這不起作用 – 2010-12-15 19:01:10

相關問題