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 计数器与互锁 [重复]的主要内容,如果未能解决你的问题,请参考以下文章