System.Threading.Interlocked
对象允许以原子操作方式进行加法(减法)和比较。似乎一个能够原子性比较不仅是相等,而且包括大于/小于的 CompareExchange 功能会非常有价值。
一个假设的 Interlocked.GreaterThan
是 IL 的特性还是 CPU 级别的功能?两者都吗?
如果没有其他选项,是否有可能在 C++ 或直接的 IL 代码中创建这样的功能并将该功能暴露给 C#?
System.Threading.Interlocked
对象允许以原子操作方式进行加法(减法)和比较。似乎一个能够原子性比较不仅是相等,而且包括大于/小于的 CompareExchange 功能会非常有价值。
一个假设的 Interlocked.GreaterThan
是 IL 的特性还是 CPU 级别的功能?两者都吗?
如果没有其他选项,是否有可能在 C++ 或直接的 IL 代码中创建这样的功能并将该功能暴露给 C#?
您可以使用InterlockedCompareExchange
来构建其他原子操作,详情请见。
public static bool InterlockedExchangeIfGreaterThan(ref int location, int comparison, int newValue)
{
int initialValue;
do
{
initialValue = location;
if (initialValue >= comparison) return false;
}
while (System.Threading.Interlocked.CompareExchange(ref location, newValue, initialValue) != initialValue);
return true;
}
long
代替int
,建议将initialValue = location;
更改为initialValue = Interlocked.Read(ref location);
。 - vgru使用这些辅助方法,您不仅可以交换值,还可以检测它是否被替换。
用法如下:
int currentMin = 10; // can be changed from other thread at any moment
int potentialNewMin = 8;
if (InterlockedExtension.AssignIfNewValueSmaller(ref currentMin, potentialNewMin))
{
Console.WriteLine("New minimum: " + potentialNewMin);
}
以下是方法:
public static class InterlockedExtension
{
public static bool AssignIfNewValueSmaller(ref int target, int newValue)
{
int snapshot;
bool stillLess;
do
{
snapshot = target;
stillLess = newValue < snapshot;
} while (stillLess && Interlocked.CompareExchange(ref target, newValue, snapshot) != snapshot);
return stillLess;
}
public static bool AssignIfNewValueBigger(ref int target, int newValue)
{
int snapshot;
bool stillMore;
do
{
snapshot = target;
stillMore = newValue > snapshot;
} while (stillMore && Interlocked.CompareExchange(ref target, newValue, snapshot) != snapshot);
return stillMore;
}
}
// this is a Interlocked.ExchangeIfGreaterThan implementation
private static void ExchangeIfGreaterThan(ref long location, long value)
{
// read
long current = Interlocked.Read(ref location);
// compare
while (current < value)
{
// set
var previous = Interlocked.CompareExchange(ref location, value, current);
// if another thread has set a greater value, we can break
// or if previous value is current value, then no other thread has it changed in between
if (previous == current || previous >= value) // note: most commmon case first
break;
// for all other cases, we need another run (read value, compare, set)
current = Interlocked.Read(ref location);
}
}
更新此前发布的帖子:我们找到了一种更好的方法,通过使用额外的锁对象来进行更大比较。我们编写了许多单元测试以验证锁和Interlocked可以一起使用,但只适用于某些情况。
代码如何工作:Interlocked使用内存屏障使读取或写入是原子操作。同步锁需要使大于比较成为原子操作。因此,现在的规则是,在这个类内部,没有其他操作在没有同步锁的情况下写入值。
我们使用这个类得到的是一个可以非常快速读取的交替值,但写入需要更多的时间。在我们的应用程序中,读取速度大约是写入速度的2-4倍。
以下是代码视图:
请参见此处:http://files.thekieners.com/blogcontent/2012/ExchangeIfGreaterThan2.png
以下是可复制粘贴的代码:
public sealed class InterlockedValue
{
private long _myValue;
private readonly object _syncObj = new object();
public long ReadValue()
{
// reading of value (99.9% case in app) will not use lock-object,
// since this is too much overhead in our highly multithreaded app.
return Interlocked.Read(ref _myValue);
}
public bool SetValueIfGreaterThan(long value)
{
// sync Exchange access to _myValue, since a secure greater-than comparisons is needed
lock (_syncObj)
{
// greather than condition
if (value > Interlocked.Read(ref _myValue))
{
// now we can set value savely to _myValue.
Interlocked.Exchange(ref _myValue, value);
return true;
}
return false;
}
}
}
lock
块内部使用Interlocked
,因为你已经通过在_syncObj
周围加锁来锁定整个类实例。 - veljkozInterlocked.Read
,但是Interlocked.Exchange
很重要,因为另一个线程可能会同时调用ReadValue()
方法(而在x86上运行时,long
不是原子的)。 - vgruInterlocked.Increment(ref long)
的一些实现所做的。只要从旧值计算新值的计算速度快,代码在循环中花费任何显著时间的危险性并不真正存在;除非其他线程有意恶意,否则最坏情况下的失败尝试次数将等于核心数。 - supercat所有交错操作在硬件中都有直接支持。
交错操作和原子数据类型是不同的东西。原子类型是一个库级别的特性。在某些平台上和对于某些数据类型,原子操作是使用交错指令来实现的。在这种情况下,它们非常有效。
在其他情况下,当平台根本没有交错操作或者对于某些特定的数据类型不可用时,库会使用适当的同步(crit_sect、mutex等)来实现这些操作。
我不确定是否真的需要 Interlocked.GreaterThan
。否则它可能已经被实现了。如果您知道一个好的例子,在哪里它可能有用,我相信每个人都会很高兴听到这个消息。
CompareExchangeGreaterThan(ref int, int, int)
来加快速度,而不需要任何自旋锁。 - makerofthings7大于/小于等于已经是原子操作了。但这并不能解决你的应用程序在并发时的安全行为。
将它们作为Interlocked家族的一部分没有意义,所以问题是:你实际上想要实现什么?