【问题标题】:C# Max counter with Interlocked [duplicate]C# Max 计数器与互锁 [重复]
【发布时间】:2021-08-29 08:20:48
【问题描述】:

我被分配了一个任务来编写一个具有以下合同的最大计数器类:

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 函数对其进行改进。你怎么看?

【问题讨论】:

  • 只是挑剔:我认为最好匹配两个 sn-ps 中的方法名称(您的第二个 sn-p 包含 Update 方法而不是 Max
  • 不仅仅是“改进”。您的解决方案不是线程安全的,因为在 Read 和 Exchange 之间另一个线程可以访问和更新对象。

标签: c# thread-safety interlocked


【解决方案1】:

您当前建议的实施方式...

... 将无法正常工作。这是因为Int32 没有Interlocked.Read 方法。

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

建议的解决方案

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

【讨论】:

    猜你喜欢
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    • 2022-07-31
    • 2011-02-20
    • 2011-12-01
    • 1970-01-01
    相关资源
    最近更新 更多