C# Max 计数器与互锁 [重复]

Posted

技术标签:

【中文标题】C# Max 计数器与互锁 [重复]【英文标题】:C# Max counter with Interlocked [duplicate] 【发布时间】: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 之间另一个线程可以访问和更新对象。 【参考方案1】:

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

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

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

建议的解决方案

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

【讨论】:

以上是关于C# Max 计数器与互锁 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

易失性与互锁性与锁定性

多线程增量和跳过 0 没有锁?

在c#中找出一个数组中出现次数最多的元素,求各种方法,要详细的代码

为啥 C# 队列或列表只有计数但数组有长度? [复制]

从另一个表中选择具有数据计数的数据[重复]

pandas 计数