The*_*eBW 1 c# multithreading process winforms
几天来,我一直试图弄清楚如何使用make console update text-box作为执行.我得出结论,线程对于同时运行表单和控制台进程是绝对必要的.进程本身是独立的程序,所以我使用标准输出来获取信息,如果我不需要它更新文本框作为其工作,它会很好,但问题是它只在执行过程后更新事实上,虽然我使用多线程.
是为运行进程并处理输出的函数创建委托的开始,以及我用于在线程和锁之间交换信息的字符串:
private static readonly object _locker = new object();
volatile string exchange = "";
delegate void CallDelegate(string filename);
Run Code Online (Sandbox Code Playgroud)
这是功能本身:
public void CallConsole(string filename)
{
Thread.CurrentThread.Name = "ProccessThread";
Thread.CurrentThread.IsBackground = false;
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.FileName = filename;
if (checkBox1.Checked)
p.StartInfo.CreateNoWindow = true;
string output;
p.Start();
while (!p.HasExited)
{
lock (_locker)
{
output = p.StandardError.ReadToEnd();
if (output.Length != 0)
{
exchange = output;
Thread.Sleep(100);
MessageBox.Show(output);
}
output = p.StandardOutput.ReadToEnd();
exchange = output;
System.Threading.Thread.Sleep(100);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是在button_click之后执行程序
private void button1_Click_1(object sender, EventArgs e)
{
textBox2.Text = "";
//Thread.CurrentThread.Name = "Main";
CallDelegate call = new CallDelegate (CallConsole);
IAsyncResult tag = call.BeginInvoke(textBox1.Text, null, null);
button1.IsAccessible = false;
while (!tag.IsCompleted)
{
string temp = "";
lock (_locker)
{
Thread.Sleep(50);
if (exchange.Length != 0)
{
temp = exchange;
exchange = "";
}
}
if (temp.Length != 0)
textBox2.Text = textBox2.Text + temp;
}
call.EndInvoke(tag);
button1.IsAccessible = true;
}
Run Code Online (Sandbox Code Playgroud)
注意:textbox1是文件路径textbox2是只读多行文本框
任何想法为什么只在CallConsole完成后更新?
一般问题:你正在循环button1_Click_1,有效地阻止UI线程.这可以防止处理其他事件 - 包括重绘等.
你不应该这样做; 相反,如果您想要轮询某些内容,请设置一个计时器来进行轮询,允许UI在"空闲"时间内处理事件.
更直接的问题:你在ReadToEnd未完成的过程中呼唤读者.这将(我相信)阻止,直到该过程完成.(在它完成之前,读者没有这样的"结束".)这意味着你有一个线程持有锁并阻塞直到进程完成 - 然后你试图获取该锁定UI线程.
我还建议让整个事情从一开始就减少轮询依赖 - 查看类中的事件Process,并尝试处理它们而不是在单独的线程中阻塞.当这些事件之一发生时,你可以回发到UI线程(带Control.Invoke)来更新UI ......那么什么需要轮询.