【发布时间】:2026-02-21 18:35:01
【问题描述】:
让我们从代码开始;
checkedUnlock 是HashSet<ulong>
_hashsetLock 是一个对象
lock (_hashsetLock)
newMap = checkedUnlock.Add(uniqueId);
对
fun 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();
}
}
}
【问题讨论】:
-
你为什么不使用并发散列集的数据类型,见*.com/a/18923091/7565574?它们通常针对并发访问进行了优化,甚至不需要锁。
-
lock有什么问题?你看过SemaphoreSlim类吗?这是一个很好的选择,而且更容易推理。 -
@ckuri 在我的代码中,这是一个仅添加的场景,并发字典已针对读取进行了优化,我无法使用它
-
@tigerswithguitars 正在查看 github.com/Microsoft/referencesource/blob/master/mscorlib/… 的代码,它使用了 spinwait & lock & monitor 的组合,有点重
-
为了清楚起见,了解更多关于为什么
lock不适用和SemaphoreSlim太重的细节会很有帮助。似乎用例很重要,这是一个有趣的问题。
标签: c# multithreading concurrency thread-safety spinwait