首页 > 解决方案 > 带互锁的 C# Max 计数器

问题描述

我被分配使用以下合同编写一个最大计数器类:

class MaxCounter
{
private int _value = int.MinValue;

public void Max(int value)
{
    if(value > _value)
    {
        _value = value;
    }
}

public int Value => _value;
}

该作业要求使用该类实现一个线程安全、非锁定的解决方案Interlocked。我想到了这个实现:

public void Update(int value)
    {
        if (value > Interlocked.Read(ref _value))
        {
            Interlocked.Exchange(ref _value, value);
            Console.WriteLine("Thread {0} updated counter to {1}.", Thread.CurrentThread.ManagedThreadId, value);
        }
    }

但我相信可以通过该CompareExchange功能对其进行改进。你怎么看?

标签: c#thread-safetyinterlocked

解决方案


您当前建议的实施...

... 不管用。因为没有Interlocked.Read办法Int32

即使存在这样的方法Int32,代码仍然无法按您的预期工作。您读取和更新值不是原子操作。在使用 读取值之后,Interlocked.Read在执行 之前Interlocking.Exchange,可能会安排另一个线程运行,而当前线程可能会“推迟”,因此第二个线程会将计数器更新为其他值。当处理器时间再次分配给第一个线程时,它会再次使用自己的值更新计数器,即使它低于_value,因为检查已经通过。

建议的解决方案

一些快速的研究使我得到了这个答案。内置Interlocked类不提供您需要的功能。因此,您可以使用我链接的答案中提出的解决方案,或者尝试使用内存屏障实现您自己的解决方案,例如(因为Int32读取和写入在设计上是原子的)。


推荐阅读