2010-08-23 63 views
0

我有一個有很多數據的數據類(電視節目表數據)。 從一側查詢數據並定期從另一側更新。 有兩個線程:第一個線程根據請求查詢數據,第二個線程定期更新數據。 爲防止鎖定,我使用數據類的兩個實例(副本):活動實例和備份實例。 最初,兩個實例都填充了相同的數據。第一個線程只從實例中讀取。 第二個線程定期更新兩個實例,如下所示:如何在此模型中使用volatile關鍵字?

  • 更新備份實例。
  • 交換備份和活動實例(即備份實例成爲活動實例)。
  • 更新備份實例。
  • 備份實例和活動實例現在都是最新的。

我的問題是:我應該如何在這裏使用volatile關鍵字?

public class data 
{ 
    // Lots of fields here. 
    // Should these fields also be declared volatile? 
} 

我已經做了引用揮發性:

public volatile data live 
public volatile data backup 
+0

volatile在多線程環境中幾乎沒用。 http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/ – leppie 2010-08-23 12:53:23

+2

@leppie該論文是關於C++中的volatile。雖然我也不傾向於在這裏使用volatile,但C#中的volatile不具有相同的語義。 – 2010-08-23 12:59:58

+0

使用* volatile *會使其失敗更快。鎖是必需的。 – 2010-08-23 13:04:12

回答

0

說實話,我只是鎖定它。正確性更容易檢查,並且刪除了對備份的需求。

隨着你的計劃在這裏,這些領域也必須是不穩定的。考慮其他情況:

public class Data 
{ 
    public int SimpleInt; 
} 

在這裏,我們只是一個簡單的公共領域,同樣適用於更現實的結構。 (順便提一下,C#中更常見的是類名的captials)。

現在考慮線程A所看到的live.SimpleInt。因爲live可以被緩存,所以我們需要把它作爲volatile。但是,請考慮當對象與backup交換後再交換回live時,則live將具有與以前相同的內存位置(除非GC已將其移動)。因此live.SimpleInt將具有與之前相同的內存位置,因此如果它不是易失性的,則線程A可能使用緩存版本live.SimpleInt。但是,如果您創建了一個新的Data對象,而不是交換進出,那麼新值live.SimpleInt將不在線程的緩存中,並且它可能是安全的非易失性的。

考慮到領域的領域也必須是不穩定的也是很重要的。

確實現在你只需要一個存儲的數據對象。新創建的對象只能被一個線程引用(因此它不會被另一個線程損壞或者損壞另一個線程),它的創建將基於從live中讀取的值,這對另一個線程來說也是安全的只有閱讀(除了一些memoisation技術,這意味着「讀取」真的寫在幕後,閱讀不會損害其他閱讀,雖然他們可以被寫作傷害)改變,而只有一個線程可見,因此只有最後寫需要關心同步的問題,因爲只有volatile或用於保護的MemoryBarrier確實應該是安全的,因爲分配引用是原子操作,並且您不再關心舊值。

0

我不認爲你會通過標記volatile來得到你想要的效果。考慮這個代碼。

volatile data live; 

void Thread1() 
{ 

    if (live.Field1) 
    { 
    Console.WriteLine(live.Field1); 
    } 
} 

在上述false的例子可以寫入控制檯如果所述第二線程調換第一線程進入if和稱爲Console.WriteLine的時間之間的livebackup引用。

如果這個問題不關心你,那麼你真正需要做的就是將live變量標記爲volatile。您不需要將data中的各個字段標記爲volatile。原因是因爲易失性讀取創建獲取柵欄內存障礙和易失寫入創建釋放柵欄內存障礙。這意味着當線程2交換引用時,所有寫入data的單個字段的寫入必須首先提交,並且當線程1想要讀取live實例的各個字段時,必須首先從主存儲器重新獲取live變量。你並不需要標記backup變量volatile,因爲它永遠不會使用線程1

advanced threading section in Joe Albahari's ebook進入細節上的volatile和語義的大量需要說明爲什麼你只需要標記您的live參考因此。