Interlocked.CompareExchange 使用GreaterThan或LessThan而不是相等

System.Threading.Interlocked对象允许加法(减法)和比较作为primefaces操作。 似乎只是不做相等的CompareExchange,而且作为primefaces比较的GreaterThan / LessThan似乎是非常有价值的。

一个假设的Interlocked.GreaterThan会不会是IL的一个特性,还是一个CPU级function? 都?

缺少任何其他选项,是否可以在C ++或直接IL代码中创建这样的function并将该function公开给C#?

更新到我在这里发表的后期文章:我们找到了一种更好的方法,通过使用额外的锁定对象来进行更大的比较。 我们编写了许多unit testing,以validation锁和Interlocked可以一起使用,但仅限于某些情况。

代码如何工作:Interlocked使用读取或写入是primefaces的内存屏障。 需要使用sync-lock来进行大于比较的primefaces操作。 所以现在的规则是在这个类中没有其他操作在没有这个同步锁的情况下写入值。

我们在这个类中获得的是一个可以非常快速地读取的互锁值,但写入需要更多一点。 在我们的应用程序中,读取速度大约快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; } } } 

您可以使用InterlockedCompareExchange构建其他primefaces操作 。

 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; } 

您如何看待这种实施:

 // 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); } } 

这实际上并不正确,但将并发视为2种forms是有用的:

  1. 锁定自由并发
  2. 基于锁的并发性

这不是真的,因为基于软件锁的并发最终是使用堆栈中某处的无锁primefaces指令实现的(通常在内核中)。 然而,锁定自由primefaces指令最终都会最终获得内存总线上的硬件锁。 因此,实际上,无锁并发和基于锁的并发是相同的。

但从概念上讲,在用户应用程序层面,它们是两种不同的处理方式。

基于锁的并发性基于“锁定”对关键代码段的访问的想法。 当一个线程“锁定”一个关键部分时,没有其他线程可能在同一个关键部分内运行代码。 这通常通过使用“互斥体”来完成,该互斥体与os调度程序接口并导致线程在等待进入锁定的临界区时变得不可运行。 另一种方法是使用“自旋锁”,这会导致线程在循环中旋转,没有任何用处,直到临界区变得可用。

无锁并发基于使用primefaces指令(CPU特别支持)的想法,这些指令由硬件保证以primefaces方式运行。 Interlocked.Increment是无锁并发的一个很好的例子。 它只调用执行primefaces增量的特殊CPU指令。

无锁并发很难。 随着关键部分的长度和复杂性的增加,它变得特别困难。 临界区中的任何步骤都可以同时由任意数量的线程同时执行,并且它们可以以极其不同的速度移动。 您必须确保尽管如此,整个系统的结果仍然是正确的。 对于类似增量的东西,它可以很简单(cs只是一条指令)。 对于更复杂的关键部分,事情会变得非常复杂。

基于锁的并发性也很难,但并不像无锁并发那么难。 它允许您创建任意复杂的代码区域,并且知道任何时候只有1个线程正在执行它。

无锁并发有一个很大的优势:速度。 如果使用正确,它可能比基于锁的并发快几个数量级。 旋转循环对于长时间运行的关键部分是不利的,因为它们会浪费CPU资源。 互斥体对于小型关键部分可能不好,因为它们会带来很多开销。 它们涉及最小的模式切换,以及最坏情况下的多个上下文切换。

考虑实现托管堆。 每次调用“新”被称为操作系统都会很糟糕。 它会破坏你的应用程序的性能。 但是,使用无锁并发可以使用互锁增量来实现gen 0内存分配(我不确定这是否就是CLR的function,但如果不是,我会感到惊讶。这可能是一个巨大的储蓄。

还有其他用途,例如无锁数据结构,如持久堆栈和avl树。 他们通常使用“cas”(比较和交换)。

但是,基于锁定的并发和无锁并发的原因实际上是等价的,因为每个实现细节都是如此。

自旋锁通常在其循环条件下使用primefaces指令(通常是cas)。 互斥锁需要在其实现中使用自旋锁或内部内核结构的primefaces更新。

primefaces指令又使用硬件锁实现。

无论如何,他们都有一套权衡取舍,通常以性能与复杂性为中心。 互斥体可以比无锁代码更快更慢。 无锁代码可能比互斥锁更复杂。 适当的使用机制取决于具体情况。

现在,回答你的问题:

执行互锁比较交换的方法,如果小于调用者不使用锁定的话。 您无法使用单个指令以相同的方式实现增量或比较交换。 您可以模拟它进行减法(计算小于),在循环中使用互锁比较交换。 您也可以使用互斥锁(但这意味着锁定,因此在名称中使用“interlocked”会产生误导)。 是否适合构建“模拟互锁通过cas”版本? 那要看。 如果代码被频繁调用,并且几乎没有线程争用,那么答案是肯定的。 如果没有,您可以将具有中等高常数因子的O(1)运算转换为无限(或非常长)循环,在这种情况下,最好使用互斥锁。

大多数时候它不值得。

使用这些辅助方法,您不仅可以交换价值,还可以检测是否替换了它。

用法如下:

 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; } } 

所有互锁操作都在硬件中提供直接支持。

互锁操作和primefaces数据类型是不同的东西。primefaces类型是库级特征。 在某些平台上,对于某些数据类型,使用互锁指令实现primefaces。 在这种情况下,它们非常有效。

在其他情况下,当平台根本没有互锁操作或者某些特定数据类型不可用时,库使用适当的同步(crit_sect,mutex等)实现这些操作。

我不确定是否真的需要Interlocked.GreaterThan 。 否则它可能已经实现。 如果你知道它有用的好例子,我相信这里的每个人都会很高兴听到这个。

大于/小于等于已经是primefaces操作。 这并没有解决您的应用程序的安全并发行为。

让他们成为联锁家庭的一部分毫无意义,所以问题是:你究竟想要实现什么目标?