使用 .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】:
让我们假设(这些限制不是基本的,只是为了简化说明)
开头currentFlags
是0
,
我们一步最多设置一个标志,
我们不接触符号位。
请注意,如果我们在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 运行时损坏吗?