[英]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.