是否可以在不锁定的情况下有条件地更新可为空的 long?
Is it possible to conditionally update a nullable long without locking?
我有 long? startTime
来保留开始时间。
我有多个线程使用非 async
方法更新 startTime
并且在单独的线程中有另一个 async
方法只读取这个值。更新值的方法如下:
if (startTime == null || (newValue != 0 && newValue < startTime))
{
startTime = newValue;
}
问题在于,写入器线程正在以非常非常高的频率更新 startTime
,导致很多锁争用。那么,有没有什么方法可以在不锁定的情况下做到这一点(或者比普通锁更好的锁定机制)?
我正在考虑使用 Interlocked
但由于 if
子句,我认为这不正确?
编辑:如果需要,我可以将其更改为不可为空。
问题结尾:
EDIT: I can change it to a non-nullable if needed.
对于不可为 null 的 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
检查。您也可以 want/need 在循环内重新计算 newValue
。
Interlocked.Read
给你取初始值。 Interlocked.CompareExchange
执行 "if the value is still the same as when I last read the value, commit my change" 并在值发生变化时获取新的当前值。
需要考虑的其他事项 - 您是否真的需要这个 "start time" 值,或者可以用一个简单的递增整数代替它吗?那将是 Interlocked.Increment
,没有循环也没有锁定,所以如果写竞争仍然很高,如果您可以适当地修改代码的其他部分,那么可能值得考虑。
我有 long? startTime
来保留开始时间。
我有多个线程使用非 async
方法更新 startTime
并且在单独的线程中有另一个 async
方法只读取这个值。更新值的方法如下:
if (startTime == null || (newValue != 0 && newValue < startTime))
{
startTime = newValue;
}
问题在于,写入器线程正在以非常非常高的频率更新 startTime
,导致很多锁争用。那么,有没有什么方法可以在不锁定的情况下做到这一点(或者比普通锁更好的锁定机制)?
我正在考虑使用 Interlocked
但由于 if
子句,我认为这不正确?
编辑:如果需要,我可以将其更改为不可为空。
问题结尾:
EDIT: I can change it to a non-nullable if needed.
对于不可为 null 的 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
检查。您也可以 want/need 在循环内重新计算 newValue
。
Interlocked.Read
给你取初始值。 Interlocked.CompareExchange
执行 "if the value is still the same as when I last read the value, commit my change" 并在值发生变化时获取新的当前值。
需要考虑的其他事项 - 您是否真的需要这个 "start time" 值,或者可以用一个简单的递增整数代替它吗?那将是 Interlocked.Increment
,没有循环也没有锁定,所以如果写竞争仍然很高,如果您可以适当地修改代码的其他部分,那么可能值得考虑。