2013-10-09 70 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