簡體   English   中英

訪問將在C#中的另一個線程中更新的參考對象是否安全?

[英]Is it safe to access a reference object that will be updated in another thread in C#?

關於stackoverflow也有一些類似的問題,但是對於目前的情況,我還沒有得到答案:

  • 我在多線程訪問的字典中有某種緩存
  • 如果正在進行更新,則線程是否訪問“舊”版本都沒有關系

    這是我訪問字典的方式:

     if (m_Dictionary != null && m_Dictionary.ContainsKey(key)) { return await Task.FromResult(m_Dictionary[key]); } 

    當某些元素不在緩存中時,這就是我如何更新引用的方式(例如(我可以進行多次更新):

     var newDictionary = Load(); lock (m_Lock) { m_Dictionary = newDictionary; } 

所以問題是:我是否會遇到一些問題,即閱讀一些部分更新的參考書? 由於它不是32位值(它可以在64位體系結構上運行),在我看來這是不安全的,因為不能保證原子性。 然后將所有讀取訪問權限從變量更改為此方法是否足夠:

private Dictionary<string, int> GetDictionary()
{
    lock (m_Lock)
    {
       return m_Dictionary;
    }
}

這部分是不安全的:

if (m_Dictionary != null && m_Dictionary.ContainsKey(key))
{
    // this could still throw KeyNotFound because 
    // it can be a different Dictionary than in the previous line
    return await Task.FromResult(m_Counterparts[key]);
}

因此,您也必須用lock (m_Lock){}將其包圍。

但是您的要求應該滿足:

var localDictionary = GetDictionary();  // a local copy is thread-safe

if (localDictionary.ContainsKey(key))   // or TryGetvalue
{
    return await Task.FromResult(localDictionary[key]);
}
else ...

由於您要一次性更新整個詞典,因此對引用的實際訪問是安全的。

由於它不是32位值(它可以在64位體系結構上運行),在我看來這是不安全的,因為不能保證原子性。

在64位體系結構上,以64位對齊的64位值具有原子訪問權限。 引用訪問始終是原子的。

但是,仍然有兩件事可能會出錯:

其中之一是來自一個核心的更新沒有被另一個核心看到。 您沒有此問題,因為您在鎖中進行了寫入,並且.NET鎖具有隱式的內存屏障。 (實際上,您不需要完全鎖定,只需進行易失性寫入即可)。

另一個是讀取之間的種族。 一次讀取的m_dictionary可能不是下一次讀取的m_dictionary 將其讀入局部變量,然后對該局部變量進行操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM