是否可以有条件地更新可为空的long而不进行锁定?

时间:2018-11-29 09:58:48

标签: c# multithreading locking interlocked

我有long? startTime来保留开始时间。

我有多个具有非async方法的线程,它们正在更新startTime,并且在单独的线程中还有另一个async方法,它只能读取该值。更新值的方法如下:

if (startTime == null || (newValue != 0 && newValue < startTime))
{
    startTime = newValue;
}

问题在于,写线程正在以非常高的频率更新startTime,从而导致了很多争用锁的情况。那么,有什么方法可以不用锁定(或者比普通锁定更好的锁定机制)来做到这一点?

我正在考虑使用Interlocked,但是由于存在if子句,我认为这是不正确的吗?

编辑:如果需要,我可以将其更改为不可为空的

1 个答案:

答案 0 :(得分:2)

问题结尾:

  

编辑:如果需要,我可以将其更改为不可为空的

对于不可为空的long,您需要检查和更新循环(类似这样):

var current = Interlocked.Read(ref startTime);
while(current > newValue)
{
  var other = Interlocked.CompareExchange(ref startTime, newValue, current);
  if(other==current) break;
  current = other;
}

您可以使while子句条件任意复杂,它们实际上是您的if检查。您可能还希望/也需要在循环内重新计算newValue

Interlocked.Read为您获取初始值。 Interlocked.CompareExchange会执行“如果该值仍与我上次读取该值时相同,请提交更改”,如果该值已更改,则还会获取新的当前值。

要考虑的其他事项-您实际上是否需要此“开始时间”值,还是可以在其中放置一个简单的递增整数?那将是Interlocked.Increment,没有循环且没有锁定,因此,如果您可以适当地修改代码的其他部分,那么这里的写争用仍然很高,可能值得考虑。