如何在非gui线程中获取任务完成通知

时间:2011-07-25 18:00:44

标签: c# multithreading .net-4.0 task-parallel-library

背景:我曾经在Form Load期间调用存储过程。但是,由于这会导致UI体验不理想,我将我的SP调用放在Shown事件中的自己的任务中。由于这通常是表单显示过程中的最后一个事件,因此它比将表单加载事件中的内容更好。我有:

private void MainForm_Shown(object sender, EventArgs e)
{
   dbCheckTask = Task<bool>.Factory.StartNew(RunSPAndCheckStuff());

  // both of below run on the GUI thread.

  // if I print the thread ID in mycallback it is the GUI thread id
  dbCheckTask.ContinueWith(mycallback());  

  // I also tried below. But obviously, that too runs on the GUI thread
  mycallback(dbCheckTask.Result)

}

因为它们在GUI线程上触发,我的启动表单绘制仍然既不是即时的也不是平滑的。如何在不诉诸事件的情况下在非GUI线程上完成任务完成回调?每当任务完成并且出现问题并且只有在出现问题时(bool结果返回false),用户才会弹出一个消息框。在那之前,他可以继续在表格上做其他非数据库相关的事情。请告诉我如何在非gui线程中获取任务结果回调和任务结果。谢谢

4 个答案:

答案 0 :(得分:3)

所有这些内容都可以在您可以下载here的Async语言扩展程序中得到最佳解决,并且主页为here

它将asyncawait关键字引入C#和VB,使您可以编写在UI和后台线程之间来回切换的代码,即使在单个方法中也是如此。编译器会将其转换为任务,延续,错误捕获等,而不必担心任何问题。你会感兴趣的例子是:

    public async void AsyncSwitchToCPU()    {
    Console.WriteLine("On the UI thread.");

    // Switch to a thread pool thread:
    await new SynchronizationContext().SwitchTo();  

    Console.WriteLine("Starting CPU-intensive work on background thread...");
    int result = DoCpuIntensiveWork();
    Console.WriteLine("Done with CPU-intensive work!");

    // Switch back to UI thread
    await Application.Current.Dispatcher.SwitchTo();                

    Console.WriteLine("Back on the UI thread.  Result is {0}.", result);
}

public int DoCpuIntensiveWork()
{
    // Simulate some CPU-bound work on the background thread:
    Thread.Sleep(5000);
    return 123;
}

这甚至还有一个上线许可证(MS的一些保留)。从F#借来的非常优雅的东西。

Rgds Gert-Jan

答案 1 :(得分:1)

您应该考虑使用异步API,而不是在后台线程中调用同步版本:

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.beginexecutenonquery.aspx

这样做的好处是不会阻塞任何线程,我相信将在ThreadPool线程上调用回调,例如不在GUI线程上。从那里,您可以使用Invoke / BeginInvoke将任何GUI调用封送回GUI线程。

答案 2 :(得分:1)

我个人使用BackgroundWorker。让回调在任务线程上运行的一种方法是修改方法调用和任务创建,如下所示:

private void MainForm_Shown(object sender, EventArgs e)
{
    dbCheckTask = Task<bool>.Factory.StartNew(() => RunSPAndCheckStuff(mycallback));
    ...
}

private bool RunSPAndCheckStuff(Action<bool> callback)
{
    bool result = false;
    // Do stuff
    callback(result);
    return result;
}

答案 3 :(得分:0)

为什么不这样做:

Task.Factory.StartNew(()=>WorkerMethod());

将WorkerMethod()定义为:

void WorkerMethod()
{
     RunSPAndCheckStuff(); // this blocks until finished
     DoSomeMoreStuff(); // then this continuous
}

否则请提供更多有关您想要完成的内容的详细信息。