2011-09-02 40 views
12

我想要做類似下面的事情 - 基本上我調用異步操作,它將在另一個線程中調用回調,並且我想等待它完成「內聯」。我擔心的是,更改跨線程共享的變量(bar &事件)可能由於存儲在寄存器中而不同步。如果它們是成員變量,我可以將它們標記爲volatile,但volatile不能用於在堆棧上創建的局部變量。我可以使用成員變量,但我認爲它的清潔劑不會讓我的課程保持全部本地化。在線程之間共享局部變量是否安全(通過回調閉包)?

Bar bar = null; 
ManualResetEvent event = new ManualResetEvent(false); 

foo.AsyncOperation(new Action(()=>{  
    // This delegate will be called in another thread 
    bar = ... 
    event.Set(); 
})); 

event.WaitOne(timeout); 
// use bar 
+2

注意:除非你做的東西AsyncOperation'和'WaitOne'之間'否則,你可能也運行同步 –

+0

這個問題是相關的:http://stackoverflow.com/questions/6581848/memory-barrier-發電機/ 6932271#6932271 –

+0

@Marc - 好點,但我調用的API本質上是異步的。它基於通過網絡發送到服務器的消息。在AsyncOperaton中設置一條消息,並在有回覆時通知回撥。我大部分時間都是異步使用它,但在這種特殊情況下,我想等待結果。我在WaitOne中包含了一個超時,以防止回覆未到。 – Shane

回答

6

是的,它會正常工作。讀到這裏

http://www.albahari.com/threading/part4.aspx

The following implicitly generate full fences:Setting and waiting on a signaling construct

,並在信令構建ManualResetEvent是包括在內。

如果你想知道什麼是full fence是,在同一頁:

全部圍欄的最簡單的內存屏障是完整的內存 屏障(全柵欄)防止任何類型的指令重新排序 或在圍欄周圍緩存。調用Thread.MemoryBarrier生成一個 full fence;

+0

很酷;如果'WaitOne'充當圍欄,則是安全的。但是,我確實會用MSDN來記錄這個http://msdn.microsoft.com/en-us/library/58195swd.aspx –

+2

@Marc關於線程安全和圍牆的msdn文檔是相當缺乏的,如果我沒有記錯的話,但是http://msdn.microsoft.com/en-us/library/ms686355(v=vs.85).aspx'以下同步函數使用適當的障礙來確保內存排序:''Wait functions''和'Functions信號同步對象' – xanatos

+0

排序,然後;我會刪除我的答案 –

4

我覺得你的代碼將工作 - 關閉將取消再放入即使他們只是在堆棧變量堆(該ManualReseetEvent肯定不會是)。

但是,爲什麼你不把事件放在event.WaitOne()之後的繼續(塊是event.Set被調用)?我認爲這應該是處理這種情況的首選方式,並且不會以這種方式遇到麻煩(你根本不需要外側的酒吧,而且你仍然可以使用MRE來檢查)。

我會考慮將其轉換爲使用任務對象的操作 - 這將一次性解決所有這些問題(例如,從您的AsyncOperation返回一個任務)。然後,您可以等待任務的結果,並使用返回的酒吧......

class Foo 
{ 
// ... 
private Task<Bar> AsyncOperation(Task<Bar> initializeBar) 
{ 
    return initializeBar 
      .ContinueWith(
      bar => { 
        /* do your work with bar and return some new or same bar */ 
        return bar; 
        }); 
} 
} 

,並使用它像這樣:

var task = foo.AsyncOperation(Taks.Factory.StartNew(() => { /* create and return a bar */ })); 
var theBar = task.Result; // <- this will wait for the task to finish 
// use your bar 

PS:封閉基本上都會將它們包裝成只是一個類-object;) PPS:我很難在沒有使用AsyncOperation的情況下測試此代碼,但它應該通過錯誤的拼寫/打字工作來模擬語法錯誤我製作

+0

我不太確定 - 它如何保證工作?通常的數據/排序規則只適用於單線程...... –

+0

顯然你比我知道更多關於這些東西 - 問題是如果這段代碼被放入某種寄存器(並且我認爲)被重用/在另一個線程中重新創建),我認爲* this *肯定不會發生。我認爲我看到了類似於F#使用的異步內容的東西,並且誠實地說:我使用了類似的東西(使用ManualResetEvents - 本地定義來同步線程)安靜了很多,並且從未遇到過麻煩。但我不是一個可靠的人 - 維扎扎德 - 也許你可以指出問題出在哪裏,而不是暗示它? (沒有offens - 真的很感興趣) – Carsten

+0

哦,等等 - 你(當然)在考慮酒吧對象,我猜...嗯 - 這確實可能會造成麻煩... – Carsten

相關問題