TPL如何进行'回叫'

时间:2012-03-08 12:10:23

标签: c# multithreading callback task-parallel-library

我有一个小应用程序需要为多个连接测试SQL连接字符串(每个连接一次一个地完成)。为此,我暂时设置ConnectionTimeout = 5,以避免在连接无效时等待很长时间,并ConnectionTimeout = 0(等待永远),比方说。

为了避免在我们尝试Open()错误连接时悬挂用户界面(即使使用ConnectionTimeout = 5,等待SqlException的时间可能长达20秒),我想要运行使用任务并行库(TPL)在单独的线程上进行测试。所以我将我的新主题分拆出来:

Task<bool> asyncTestConn = Task.Factory.StartNew<bool>
    (() => TestConnection(conn, bShowErrMsg));
return asyncTestConn.Result;

问题是这仍然是锁定UI(显然),因为它在返回调用者之前等待结果。如何在从异步Task获取最终结果的同时允许代码将控制权返回给UI(释放GUI)?

另外,在Task MessageBox.Show("Some message")范围内我可以合法地BackgroundWorkers吗?这对{{1}}不起作用,默认情况下,此池化线程是后台线程;但它似乎不是一个问题。谢谢你的时间。

2 个答案:

答案 0 :(得分:5)

对于TPL,ContinueWith正是您想要的。扩展Henk的答案:

var asyncTestConn = Task.Factory.StartNew(() => TestConnection(conn, bShowErrMsg));
// Henk's "MyFinishCode" takes a parameter representing the completed
// or faulted connection-testing task.
// Anything that depended on your "return asyncTestConn.Result;" statement
// needs to move into the callback method.
asyncTestConn.ContinueWith(task =>
    {
        switch (task.Status)
        {
            // Handle any exceptions to prevent UnobservedTaskException.
            case TaskStatus.Faulted: /* Error-handling logic */ break;
            case TaskStatus.RanToCompletion: /* Use task.Result here */ break;
        }
    },
    // Using this TaskScheduler schedules the callback to run on the UI thread.
    TaskScheduler.FromCurrentSynchronizationContext());

答案 1 :(得分:4)

你是对的,这是等待发生的地方:

 return asyncTestConn.Result;

您可以在TestConnection()的尾部构建完成代码或使用Continuation:

// untested
//Task<bool> asyncTestConn = Task.Factory.Create<bool> (
Task<bool> asyncTestConn = new Task<bool> (
    () => TestConnection(conn, bShowErrMsg));
asyncTestConn.ContinueWith(MyFinishCode);
asyncTestConn.Start()
  

我可以合法地MessageBox.Show("Some message")吗?

实际上是,MessageBox是线程安全的。也应该可以从Bgw。

但是你要延长任务的寿命,这不是一个好主意。