在等待另一个线程完成它的工作时解锁主线程

时间:2014-07-30 20:43:08

标签: c# .net multithreading winforms

在WinForms应用程序中,我启动工作线程,将数据添加到根XElement

然后在主线程中我需要等待工作线程完成它的工作(以获得完整的XElement),并将此XElement输出到textarea

如果我在主线程上调用.Join() - 它会冻结,直到另一个线程停止(并且用户无法单击主窗体上的任何按钮)。

是否可以在等待另一个线程完成它的工作时取消阻塞主线程?

我试过了:

1

BeginInvoke(new Action(() => {
     XmlManager.whReady.WaitOne();
     xDocString = xResultDoc.ToString();
}));

2

string xDocString = String.Empty;
new Thread(() => { xDocString = XelementToString(); }).Start();

txtXmlTree.Text = xDocString;

public string XelementToString() {
    XmlManager.whReady.WaitOne();
    return xResultDoc.ToString();
}

但它没有效果。

EventWaitHandle XmlManager.whReady.WaitOne();在工作线程关闭之前就是.Set()

2 个答案:

答案 0 :(得分:1)

是的,您可以使用async / await

string docString = await Task.Run(() => {
 XmlManager.whReady.WaitOne();
 return xResultDoc.ToString();
}).ConfigureAwait(true);

//Execution flow will resume here once the thread is done.
....
//Now do something here with the text (e.g. display it).
...

例如,如果您想在点击按钮上运行此功能,则可以(请注意 async 修饰符):

private async void button1_Click(object sender, EventArgs e) 
{
  ...The code above goes here...
}

至于为什么你的代码没有按预期工作(你的两次尝试):

  1. 您的代码是阻塞的,因为它会导致在创建主窗体句柄的线程上执行操作(因此UI线程)。您通常从另一个(非UI)线程调用BeginInvoke来告诉UI执行某些操作。
  2. 您启动一个主题,然后立即希望xDocString准备好使用。它不起作用。到执行此行时txtXmlTree.Text = xDocString;,线程可能已经或可能没有完成执行(很可能没有完成)。
  3. 我希望你现在明白为什么await是更好的选择。您不必将工作程序与主线程同步,您不必担心上下文切换并确保UI代码在UI线程上执行。

答案 1 :(得分:0)

您可以使用BackgroundWorker类,因为它是WinForm应用程序。

BackgroundWorker将让子任务在后台运行,并在完成后通知主表单(以及进度,如果需要),因此主表单将能够在文本中显示输出区域任务完成后区域。