加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何以线程安全的方式将控制台程序的输出重定向到文本框?

发布时间:2020-12-15 08:19:05 所属栏目:百科 来源:网络整理
导读:我无法将控制台输出重定向到 Windows窗体文本框.问题与线程有关.我正在以下列方式运行控制台应用程序, private void RunConsoleApp(){ Process proc = new Process(); proc.StartInfo.FileName = "app.exe"; proc.StartInfo.Arguments = "-a -b -c"; proc.St
我无法将控制台输出重定向到 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 Passant所指出的那样)

问题是该应用程序由于线路而陷入“致命的拥抱”,

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();
}

解决方法

proc.WaitForExit();

它被称为死锁.您的主线程被阻止,等待进程退出.这使它无法承担基本职责.就像保持UI更新一样.并确保调度Control.Invoke()请求.这会阻止AppendText()方法完成.这会停止退出的过程.这会阻止你的UI线程通过WaitForExit()调用. “致命的拥抱”,又名死锁.

你不能阻止你的主线程.请改用Process.Exited事件.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读