Interlocked.Exchange() 具有依赖于读取锁定变量的自定义条件
Interlocked.Exchange() with custom condition that relies in reading the locked variable
原码:
var can = rateLock.WaitAsync();
if (can.IsCompletedSuccessfully) // for safety but do I need it?
{
if (!increase)
{
errorRate = (byte)(errorRate - Convert.ToByte(errorRate > 0));
}
else
{
errorRate++;
}
if (errorRate > 50)
{
TimerStop(true);
}
rateLock.Release();
}
修改为:
if (increase)
{
if (Interlocked.Increment(ref errorRate) > 50)
{
TimerStop(true);
}
}
else
{
Interlocked.Exchange(ref errorRate, (errorRate - Convert.ToInt32(errorRate > 0)));
}
问题:
如您所见,"decrementing" 部分依赖于需要读取两次的相同变量值,然后执行布尔和减法运算,所有这些都在互锁上下文之外。
我真的很喜欢没有额外的 SempahoreSlim(异步环境)的可能性 - 有什么方法可以使自定义条件的递减工作避免大量的 IF(我需要保持 errorRate >=0)?
您可以使用 CompareExchange pattern 进行更复杂的操作:
int initialErrorRate, int computedErrorRate;
do
{
initialErrorRate = errorRate;
if (increase)
{
computedErrorRate = initialErrorRate + 1;
}
else
{
computedErrorRate = initialErrorRate - Convert.ToInt32(initialErrorRate > 0);
}
}
// set new error rate only when it was not changed inbetween, otherwise try again
while (initialErrorRate != Interlocked.CompareExchange(ref errorRate, computedErrorRate, initialErrorRate);
if (errorRate > 50)
{
TimerStop(true);
}
原码:
var can = rateLock.WaitAsync();
if (can.IsCompletedSuccessfully) // for safety but do I need it?
{
if (!increase)
{
errorRate = (byte)(errorRate - Convert.ToByte(errorRate > 0));
}
else
{
errorRate++;
}
if (errorRate > 50)
{
TimerStop(true);
}
rateLock.Release();
}
修改为:
if (increase)
{
if (Interlocked.Increment(ref errorRate) > 50)
{
TimerStop(true);
}
}
else
{
Interlocked.Exchange(ref errorRate, (errorRate - Convert.ToInt32(errorRate > 0)));
}
问题: 如您所见,"decrementing" 部分依赖于需要读取两次的相同变量值,然后执行布尔和减法运算,所有这些都在互锁上下文之外。
我真的很喜欢没有额外的 SempahoreSlim(异步环境)的可能性 - 有什么方法可以使自定义条件的递减工作避免大量的 IF(我需要保持 errorRate >=0)?
您可以使用 CompareExchange pattern 进行更复杂的操作:
int initialErrorRate, int computedErrorRate;
do
{
initialErrorRate = errorRate;
if (increase)
{
computedErrorRate = initialErrorRate + 1;
}
else
{
computedErrorRate = initialErrorRate - Convert.ToInt32(initialErrorRate > 0);
}
}
// set new error rate only when it was not changed inbetween, otherwise try again
while (initialErrorRate != Interlocked.CompareExchange(ref errorRate, computedErrorRate, initialErrorRate);
if (errorRate > 50)
{
TimerStop(true);
}