使用 .NET 中的 Interlocked 类实现按位运算

Posted

技术标签:

【中文标题】使用 .NET 中的 Interlocked 类实现按位运算【英文标题】:Implementing a bitwise operation using the Interlocked class in .NET 【发布时间】:2015-07-27 15:21:28 【问题描述】:

我正在尝试在多线程 .NET 应用程序中的共享变量中设置位标志,但在托管 Interlocked 类中找不到与本机 InterlockedOr 函数的并行。我想出了以下代码来执行 |= 赋值,但理论上无限循环的可能性让我感到不舒服:

long currentValue;
long updatedValue;

do

    // Spin until successful update. Value must be read using Interlocked.Read()
    // to be truly atomic on 32 bit systems (see MSDN).
    currentFlags = Interlocked.Read(ref _currentFlags);
    updatedValue = currentFlags | flag;
 while (currentFlags != Interlocked.CompareExchange(ref _currentFlags, updatedValue, currentFlags));

是否可以仅使用 Interlocked 类中内置的函数以更安全的方式实现?如果可能,我想避免涉及显式锁定的解决方案。

【问题讨论】:

虽然在使用CompareExchange 时可能会出现无限循环,但这种情况不太可能发生,可以忽略不计。 .NET Framework 广泛使用了这种技术,包括在所有并发集合中以实现无锁同步。 只有当其他线程同时将标志重置为零时,您才会获得无限循环,并且足够灵活,每次都可以击败您的线程,进行无限次尝试。如果发生这种情况,你有更大的问题需要解决,弄清楚为什么“敏捷”线程会做它所做的事情。我认为您的解决方案与Interlocked 一样好。 【参考方案1】:

让我们假设(这些限制不是基本的,只是为了简化说明)

开头currentFlags0, 我们一步最多设置一个标志, 我们不接触符号位。

请注意,如果我们在currentFlags 中将位k 设置为1 一次,我们可以将or 替换为+ 1L << k。所以我们可以使用辅助数组 set 来记住已经设置了哪些位,如果需要,可以使用 Interlocked.Add

long currentFlags = 0;
int[] set = new int[sizeof(long) * 8];

....

int k = ...; // bit to set
if(Interlocked.Exchange(ref set[k], 1) == 0)
    Interlocked.Add(ref currentFlags, 1L << k);

【讨论】:

以上是关于使用 .NET 中的 Interlocked 类实现按位运算的主要内容,如果未能解决你的问题,请参考以下文章

当 Interlocked 类可用时,为啥在 .NET 中使用 SyncLocks 进行简单操作?

Java 相当于 .Net 的 Interlocked 类是啥?

Interlocked.Increment 溢出会导致 .NET 运行时损坏吗?

使用Interlocked.Increment的C#对象池

如何为 C# 中的枚举类型应用 InterLocked.Exchange?

[OS] 多线程--原子操作 Interlocked系列函数