[英]Do I need to use interlocked when there is a closure?
考慮這段代碼在counter
周圍創建一個閉包:
uint counter = 0xFFFF;
someList.AsParallel().ForEach(a => { uint tmp = ++counter });
(請暫時擱置在並行foreach中使用計數器的明顯問題)。
tmp
會評估為0x0000還是0x1FFFF?
我的理由:要將counter
從0xFFFF遞增到0x10000,至少需要一個可被多線程中斷的雙字節CPU指令。 如果它被中斷,則有可能只更新一個字節的counter
- 它可以暫時設置為0x00000或0x1FFFF。
我應該把它寫成:
uint counter = 0xFFFF;
someList.AsParallel().ForEach(a => { uint tmp = Interlocked.Increment(counter) });
...?
如果我擺脫AsParallel
,我完全安全嗎?
是的,你需要Interlocked.Increment
,閉包不會改變這個操作不是線程安全的事實。 什么閉包將把你的lambda表達式提升到一個顯示類中,並在每次迭代時重復使用相同的類,這將導致多個線程遞增計數器。
反編譯看起來像這樣:
public class C
{
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public uint counter;
internal void <M>b__0(int a)
{
uint num = this.counter + 1u;
this.counter = num;
}
}
public void M()
{
C.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new C.<>c__DisplayClass0_0();
<>c__DisplayClass0_.counter = 65535u;
List<int> source = new List<int> {
1,
2,
3
};
source.AsParallel<int>().ForAll(new Action<int>(<>c__DisplayClass0_.<M>b__0));
}
}
如果我擺脫
AsParallel
,我完全安全嗎?
只要在迭代時列表或計數器沒有變異,你應該沒問題。 從您的示例中,您無法知道您正在使用的數據的實際位置,但假設一切都是方法范圍本地,您會沒事的。
對。 Parallel是多線程的語法糖。 你仍然需要線程安全。 如果你是單線程,你顯然不需要Interlocked(或線程安全)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.