从特定线程调用方法

时间:2012-11-28 16:19:32

标签: c# multithreading task-parallel-library

如何在调用onCompleteCallBack的同一个线程上调用SomeAsyncMethod方法?

public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
    // get the current thread 
    /* var ThisThread = Thread.CurrentThread. */

    Task.Factory.StartNew( () =>
    {
        Thread.Sleep( 1000 );// do some work;

        // lastly call the onCompleteCallBack on 'ThisThread'
        onCompleteCallBack( "some result" );

        // I am looking for something like:
        /* ThisThread.Invoke("some result"); */
    });
}

2 个答案:

答案 0 :(得分:5)

虽然您无法保证在相同的主题上调用回调,但您可以保证在相同的 Synchronization Context 中调用它(假设原始呼叫中存在一个)。

public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
    // get the current context
    var context = SynchronizationContext.Current;

    Task.Factory.StartNew( () =>
    {
        Thread.Sleep( 1000 );// do some work;

        // lastly call the onCompleteCallBack on 'ThisThread'
        onCompleteCallBack( "some result" );

        // I am looking for something like:
        context.Post(s => onCompleteCallBack ("some result"), null); 
    });
}

例如,在Windows窗体或WPF程序中,上面将确保在GUI线程上调用回调(相应地通过消息循环或调度程序)。类似于ASP.NET上下文。

话虽如此,我同意贾斯汀哈维的观点,即回归Task<T>可能是一个更好的设计。

答案 1 :(得分:4)

实际上,如果您正在使用基于任务的异步编程,我建议您重构代码以返回Task<T>,并为您的客户端本身提供一种能力,以决定在何种上下文中调用回调方法(并促进将来迁移到C#5.0;):

public Task<string> SomeMethodAsync()
{
   return Task.Factory.StartNew(() => "some result");
}

如果您确定知道要从UI线程调用此方法,可以使用以下命令:

var task = SomeMethodAsync();
task.ContinueWith(t => textBox.Text = t.Result, TaskScheduler.FromSynchronizationContext);

这种方法更好,因为它提供了更清晰的关注点分离,并且能够在任何上下文中使用异步方法,而不依赖于同步上下文。一些客户端可以从UI线程调用此方法(在这种情况下TaskScheduler.FromSynchronizationContext将按预期运行 - 您的“延续”将在UI线程中调用),其中一些可以使用非UI线程中的方法没有这样的要求,比如在同一个启动异步操作的线程中处理结果。

Task<T>是一个完美的类,它将异步操作表示为first class object,它不仅有助于获得更多的声明性代码,而且更加清晰,易于阅读和易于测试(您可以轻松地模拟此方法并返回“假”任务对象)。