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

goo*_*ate 22 c# c++ il interlocked interlocked-increment

System.Threading.Interlocked对象允许加法(减法)和比较作为原子操作.似乎只是不做相等的CompareExchange以及作为原子比较的GreaterThan/LessThan将是非常有价值的.

Interlocked.GreaterThanIL 的假设特征还是CPU级功能?都?

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

Ray*_*hen 45

你可以构建其他原子操作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;
}
Run Code Online (Sandbox Code Playgroud)

  • @Nnoel在CompareExchange(原子性)之前,所有步骤都没有外部可见性.如果你看一下大多数处理器,唯一的原子核操作是CompareExchange; 其他一切都是建立在它之上的. (8认同)
  • 请注意:如果使用`long`而不是`int`,最好将`initialValue = location;`更改为`initialValue = Interlocked.Read(ref location);`. (6认同)

Ant*_*rin 5

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

用法如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

这里是方法:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 3

更新我在这里发表的后一篇文章:我们找到了一种更好的方法,通过使用额外的锁对象来进行更大的比较。我们编写了许多单元测试来验证锁和 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为你真的不需要在“lock”块中使用“Interlocked”,因为你已经通过锁定“_syncObj”来锁定整个类实例 (15认同)
  • @veljkoz:“Interlocked.Read”在锁内不是必需的,但“Interlocked.Exchange”很重要,因为另一个线程可能会同时调用“ReadValue()”方法(并且“long”在 x86 上运行时不是原子的)。 (3认同)