2013-10-09 67 views
0

我正在使用不使用async的多线程库,而是使用传统线程和回调。如何等待线程回调?

var connection = new SomeLib(); 
connection.OnConnected += (x) => { /* This is called from separate thread */ } 
connection.Connect(); 

我从一个async函数调用的代码,像这样:

public async Task<Boolean> MyFunc() 
{ 
    var connection = new SomeLib(); 
    connection.OnConnected += (x) => { /* This is called from separate thread */ } 
    connection.Connect(); 

    // ... 

    // Need to return after OnConnected has been fired. 
    return true; 
} 

如何使用await有我的功能“等待” OnConnected回调被称为?

+2

你想要返回什么字符串?感觉要做的第一件事就是编写一个'ConnectAsync'方法(或者可能的扩展方法),它可能使用一个'TaskCompletionSource'作为跟踪它的一个相当简单的方法。 –

+0

该字符串不重要。这只是一个玩具的例子。通过编写ConnectAsync方法,你的意思是什么?我应该提及,我无法更改我正在使用的库的来源。 –

+0

@JonSkeet很抱歉,我将删除我的评论 –

回答

3

的以下内容适用于EventHandler类型事件 - 但您可以轻松调整它们以适用于不同的签名委托。首先,辅助函数(EventToATaskAsync)whi ch需要加法器和移除代表来设置/解除事件:

请注意,使用此机制的缺点是您需要为每个包装的异步操作编写扩展方法。

public static Task<A> EventToTaskAsync<A>(Action<EventHandler<A>> adder, Action<EventHandler<A>> remover) 
{ 
    System.Threading.Tasks.TaskCompletionSource<A> tcs = new TaskCompletionSource<A>(); 
    EventHandler<A> onComplete = null; 
    onComplete = (s, e) => 
    { 
     remover(onComplete); 
     tcs.SetResult(e); 
    }; 
    adder(onComplete); 
    return tcs.Task; 
} 

然后,我通常用一个扩展调用来包装它,以将任务功能添加到现有类。在下面的例子中,我加入BeginAsync到故事板(但你可以做到这一点,以使用该事件机制几乎任何东西):

public static Task BeginAsync(this Storyboard storyboard) 
    { 
     return EventToTaskAsync<object>(
       e => { storyboard.Completed += e; storyboard.Begin(); }, 
       e => storyboard.Completed -= e); 
    } 

希望有所帮助。

-1

你可以用等待手柄来做到这一点。首先定义的AutoResetEvent:

private waitForConnect = new AutoResetEvent(false); 

在OnConnected处理,触发手柄:

waitForConnect.Set(); 

在调用连接功能,等待句柄触发:

connection.Connect(); 
waitForConnect.WaitOne(); // This will sleep the thread until connected 
+1

异步方法(无论是回调式还是'async'''await')的重点在于它们*不会阻塞*。所以我认为这样做没有任何意义。 – svick

+0

@svick:的确,我的错误... – Bigjim