Interlocked类:读先写竞态条件问题及无阻塞解决方案咨询
非阻塞式解决竞态条件问题
你说的没错,问题就出在检查条件和执行Increment的间隙。多个线程可能同时通过Interlocked.CompareExchange读到同一个小于500000的值,然后各自执行Interlocked.Increment,最后就会多出来一次递增,导致结果变成500001。
非阻塞的核心思路是把「检查+更新」做成原子操作,这里可以用循环结合Interlocked.CompareExchange来实现:
using System; using System.Threading; using System.Threading.Tasks; namespace InterlockedLearning { class Program { static int sharedVariable = 0; static void Main() { Parallel.For(0, 1000000, Func1); Console.WriteLine("Thread{0} sharedVariable: {1}", Thread.CurrentThread.ManagedThreadId, sharedVariable); Console.Read(); } public static void Func1(int val) { int currentValue; do { currentValue = Interlocked.CompareExchange(ref sharedVariable, 0, 0); // 如果当前值已经不满足条件,直接退出循环 if (currentValue >= 500000) break; // 尝试把currentValue更新为currentValue+1,只有当当前值还是currentValue时才成功 } while (Interlocked.CompareExchange(ref sharedVariable, currentValue + 1, currentValue) != currentValue); } } }
方案说明:
- 每次循环先读取当前的
sharedVariable值 - 如果值已经≥500000,直接退出,不再尝试递增
- 否则,尝试用
CompareExchange把值从currentValue改成currentValue+1:如果这期间没有其他线程修改过值,CAS操作成功,循环结束;如果被其他线程修改了,CAS失败,就重新进入循环读取新值再尝试
这样整个「检查是否可以递增+执行递增」的逻辑就变成了原子性的操作,不会出现多个线程同时通过检查然后重复递增的情况,最终结果会稳定在500000。
内容的提问来源于stack exchange,提问作者user22422035
相关产品推荐
相关产品推荐

