让我们从代码开始;
checkedUnlock
是HashSet<ulong>
_hashsetLock
是一个对象
lock (_hashsetLock)
newMap = checkedUnlock.Add(uniqueId);
vs
fun
in int
SpinWait.SpinUntil(() => Interlocked.CompareExchange(ref fun, 1, 0) == 1);
newMap = checkedUnlock.Add(uniqueId);
fun = 0;
我的理解是,在这种情况下,SpinWait
应该像lock()
一样工作,但是HashSet
中添加了更多项,有时它与锁相匹配,有时又有1至5个里面的项目,很明显它不起作用
我的理解有缺陷吗?
修改
我尝试了这一点,但似乎可行,到目前为止,我的测试显示的数字与lock()
相同
SpinWait spin = new SpinWait();
while (Interlocked.CompareExchange(ref fun, 1, 0) == 1)
spin.SpinOnce();
那么为什么要使用它而不使用SpinWait.SpinUntil()
?
修改#2
完整的小应用程序查看
在这段代码中,SpinWait.SpinUntil
有时会被炸毁(添加将引发异常),但是当它工作时,计数将有所不同,因此我对此的预期行为是错误的
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var list = new List<int>();
var rnd = new Random(42);
for (var i = 0; i < 1000000; ++i)
list.Add(rnd.Next(500000));
object _lock1 = new object();
var hashset1 = new HashSet<int>();
int _lock2 = 0;
var hashset2 = new HashSet<int>();
int _lock3 = 0;
var hashset3 = new HashSet<int>();
Parallel.ForEach(list, item =>
{
/******************/
lock (_lock1)
hashset1.Add(item);
/******************/
/******************/
SpinWait.SpinUntil(() => Interlocked.CompareExchange(ref _lock2, 1, 0) == 1);
hashset2.Add(item);
_lock2 = 0;
/******************/
/******************/
SpinWait spin = new SpinWait();
while (Interlocked.CompareExchange(ref _lock3, 1, 0) == 1)
spin.SpinOnce();
hashset3.Add(item);
_lock3 = 0;
/******************/
});
Console.WriteLine("Lock: {0}", hashset1.Count);
Console.WriteLine("SpinWaitUntil: {0}", hashset2.Count);
Console.WriteLine("SpinWait: {0}", hashset3.Count);
Console.ReadKey();
}
}
}
答案 0 :(得分:-1)
SpinWait.SpinUntil中使用的条件错误。
要反复执行直到返回true的委托。
您想旋转直到发生0-> 1过渡,所以条件应该是
Interlocked.CompareExchange(ref fun, 1, 0) == 0
随后在其他线程上对CompareExchange的调用将导致1,因此它们将等待,直到{winer}线程将fun
标志恢复为0为止。
更多说明:
fun = 0;
应该适用于x86架构,但是我不确定它在任何地方都正确。如果使用“互锁”来访问字段,则最佳做法是对所有对该字段的访问都使用“互锁”。因此,我建议改用Interlocked.Exchange(ref fun, 0)
。