Interlocked.Exchange() 具有依赖于读取锁定变量的自定义条件
Posted
技术标签:
【中文标题】Interlocked.Exchange() 具有依赖于读取锁定变量的自定义条件【英文标题】:Interlocked.Exchange() with custom condition that relies in reading the locked variable 【发布时间】:2018-08-18 21:46:59 【问题描述】:原始代码:
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)));
问题: 如您所见,“递减”部分依赖于需要读取两次的相同变量值,然后执行布尔和减法运算,所有这些都在互锁上下文之外。
我真的很喜欢没有额外的 SempahoreSlim(异步环境)的可能性 - 有没有办法在自定义条件下进行递减工作,避免大量 IF(我需要保持 errorRate >=0)?
【问题讨论】:
好吧,我有一个丑陋的版本1,我想我会坚持下去。我希望这是可行的:hastebin.com/kukohorumi.cs 但我认为平等检查仍然可以搞砸我 【参考方案1】:您可以使用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);
【讨论】:
errorRate 超过 50 后需要归零怎么办?这就是我想出的:ghostbin.com/paste/dkdup 值更改本身是线程安全的,但是如果您像在链接中那样调用它两次,则错误率可能会增加或减少两次。做什么取决于调用 TimerStop 两次或更多次是否可以,如果不是,我怀疑没有锁是可能的。如果可以多次调用 TimerStop 并快速完成,则可以将其移入循环中。以上是关于Interlocked.Exchange() 具有依赖于读取锁定变量的自定义条件的主要内容,如果未能解决你的问题,请参考以下文章
Interlocked.Exchange<T> 比 Interlocked.CompareExchange<T> 慢吗?
引用分配是原子的,那么为啥需要 Interlocked.Exchange(ref Object, Object)?