[英]C# Volatile read behavior
在C#.net ConcurrentDictionary( C#參考源 )的參考源代碼中,我不明白為什么在下面的代碼片段中需要進行易失性讀取:
public bool TryGetValue(TKey key, out TValue value)
{
if (key == null) throw new ArgumentNullException("key");
int bucketNo, lockNoUnused;
// We must capture the m_buckets field in a local variable.
It is set to a new table on each table resize.
Tables tables = m_tables;
IEqualityComparer<TKey> comparer = tables.m_comparer;
GetBucketAndLockNo(comparer.GetHashCode(key),
out bucketNo,
out lockNoUnused,
tables.m_buckets.Length,
tables.m_locks.Length);
// We can get away w/out a lock here.
// The Volatile.Read ensures that the load of the fields of 'n'
//doesn't move before the load from buckets[i].
Node n = Volatile.Read<Node>(ref tables.m_buckets[bucketNo]);
while (n != null)
{
if (comparer.Equals(n.m_key, key))
{
value = n.m_value;
return true;
}
n = n.m_next;
}
value = default(TValue);
return false;
}
評論:
// We can get away w/out a lock here.
// The Volatile.Read ensures that the load of the fields of 'n'
//doesn't move before the load from buckets[i].
Node n = Volatile.Read<Node>(ref tables.m_buckets[bucketNo]);
我有點困惑。
在從數組中讀取變量n之前,CPU如何讀取n的字段?
易失性讀取具有獲取語義,這意味着它先於其他存儲器訪問。
如果它不是用於易失性讀取,那么下一次從我們剛剛得到的Node
讀取的字段可以由JIT編譯器或體系結構推測地重新排序到讀取節點本身之前。
如果這沒有意義,想象一下JIT編譯器或體系結構讀取將分配給n
任何值,並開始推測性地讀取 n.m_key
,這樣如果n != null
,則沒有錯誤預測的分支 ,沒有管道泡沫或更糟糕的是, 管道沖洗 。
當指令的結果可以用作下一條指令的操作數時,這仍然是可能的 ,但是在流水線中。
對於易失性讀取或具有類似獲取語義的操作(例如,輸入鎖定),C#規范和CLI規范都說它必須在任何進一步的存儲器訪問之前發生,因此不可能獲得未初始化的n.m_key
。
也就是說,如果寫入也是易失性的,或者由具有類似釋放語義的操作(例如退出鎖定)保護。
如果沒有volatile語義,這種推測性讀取可能會返回n.m_key
的未初始化值。
同樣重要的是comparer
執行的內存訪問。 如果節點的對象是在沒有易失性版本的情況下初始化的,那么您可能正在閱讀陳舊的,可能是未初始化的數據。
這里需要Volatile.Read
,因為C#本身無法在數組元素上表達易失性讀取。 讀取m_next
字段時不需要它,因為它聲明為volatile
。
非常感謝你提出一個非常好的問題!
簡短的回答:評論是錯誤的(或非常令人困惑)。
更長的答案: ConcurrentDictionary中至少有兩個錯誤 。
Volatile.Read<Node>(ref tables._buckets[bucketNo])
和Volatile.Read<Node>(ref buckets[i])
是為了保護我們免於讀取可能被另一個線程更改的引用,所以我們有一個副本引用指向Node
具體實例。
而且錯誤就是即使使用這些Volatile.Read
(因為它不存在於注釋中的原因)我們可以觀察部分構造的Node
類型的對象,如果我們使用以下代碼分配引用: tables._buckets[bucketNo] = newNode
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.