从额外的线程返回结果

时间:2012-04-13 10:13:43

标签: c# multithreading

我希望在额外的线程中执行result后可以访问Heavy Process(重过程的返回结果),因为它主要是在进程UI期间不希望的生效了, 完成该过程后,可以使用result

在一些搜索过程中,查看我的文章,我得到了几种方法到 如果发生这种情况,请提供您在类似情况下了解或使用的最佳方法

这是一个我想以最佳方式处理的样本:

        public ACollection DoProcess(Document docProcess) 
        {
            ACollection result = new ACollection ();

            ThreadStart threadStart = delegate
            {
                result = MyProcess(docProcess);
            };
            var threadProcess = new Thread(threadStart);
            threadProcess.Start();    

            return result ;
}

其他可能的方法可能是IAsyncResult,BackgroundWorker,使用定时器和检查状态,而不是将结果返回到处理它的方法并将其报告给UI,直接以线程安全的方式将其发送到我们的UI控件。 ..

请在类似情况下提出您自己的意见和样本, 提前谢谢

编辑3:方法 - 基于Brian的答案

        LenzCollection myResultCollection = new LenzCollection();       

        TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

        Task.Factory.StartNew(() =>
          {
              myResultCollection = DoCollect(docProcess);
              //Task.WaitAll();

              return myResultCollection;
          }).ContinueWith((task =>
          {
              myResultCollection = task.Result;
          }), ui);

        return myResultCollection;  

它仍然没有等待,也没有给出所需的结果

4 个答案:

答案 0 :(得分:2)

只需实现一个在执行方法之前注册的事件。然后让方法在完成时引发事件。

例如:

public delegate void MyEventHandler(string result);
public class MyClass
{
  public event MyEventHandler MyEvent;
  private void Event(string result)
  {
    MyEventHandler handler = MyEvent;
    if(handler != null)
      handler(result);
  }

  public void DoSomethingLong()
  {
    //Do something
    Event("Finish");
  }
}

现在您可以像

一样运行它
MyClass.Event += MyEventHandler(On_Event);
Thread t = new Thread(MyClass.DoSomethingLong);
t.Start();    

void On_Event(string result)
{
  //Get executed when finished;
}

调用UI线程的示例

void On_Event(string result)
{
  if(this.InvokeRequired)
  {
    MyEventHandler handler = new MyEventHandler(On_Event);
    Invoke(handler, new object[] { result });
    return;
  }
  // At this point you can access your UI without having Cross-Threaded operation!
}

答案 1 :(得分:2)

在桌面(WinForms / WPF)应用程序中,最好和最简单的方法是BackgroundWorker。它旨在处理这个问题。

答案 2 :(得分:1)

如果您使用.NET Framework 4.0 or +,则可以在Task.ContinueWith中的其他线程和流程中运行该流程,例如

Process pro = null; 
 Task.Factory.StartNew(() => {
   pro =new Process(..);
   pro.Start(); 
   pro.WaitForExit(); 
}).ContinueWith(..process data recieved from the pro)

编辑

请勿使用while(...),而是使用pro.WaitForExit()

希望这有帮助。

答案 3 :(得分:1)

选项#1:

使用Task类和ContinueWith方法。

TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(() =>
  {
    var result = MyProcess(docProcess);
    return result.ToString();
  }).ContinueWith((task =>
  {
    textBox1.Text = task.Result;
  }, ui);

您必须记住将正确的同步上下文传递到ContinueWith方法。您可以使用ui变量了解我是如何做到的。

选项#2:

使用新的asyncawait关键字。 1

private async void SomeButton_Click(object sender, EventArgs args)
{
  textBox1.Text = await Task.Run(() =>
    {
      var result = MyProcess(docProcess);
      return result.ToString();
    });
}

显然,这对眼睛来说要容易得多,而且所有的编组和同步环境都适合你。


1 新的关键字将在C#5.0中提供,但您现在可以通过Async CTP使用它们。 CTP使用TaskEx代替Task