根据比较结果自动交换值
我有一个非常简单的操作,需要以原子方式完成:
if (a > b)
b = a
其中 a 和 b 是整数
编辑:,a 是本地的。
在 C# 中是否有快速的方法来做到这一点?如果可能的话,我想避免手动锁定。我查看了 Interlocked.CompareExchange,但据我了解,这仅测试相等性。
谢谢!
I have a very simple operation that needs to be done atomically:
if (a > b)
b = a
where a and b are ints
EDIT: and a is local.
Is there a fast way to do this in C#? I'd like to avoid locking manually if possible. I've looked at Interlocked.CompareExchange, but as I understand it, this only tests for equality.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
规范的方法是在循环中使用互锁比较交换:(
伪代码,因为我懒得查找在 C# 中进行互锁交换的正确方法)。
正如您所看到的,除非您有最重要的效率问题,否则使用普通的旧互斥体要简单得多且更具可读性。
编辑:这假设
a
是一个局部变量或者至少不受异步写入的影响。如果a
和b
都可以在你背后修改,那么就没有无锁的方式来原子地执行此更新。 (感谢 silev 指出这一点)。The canonical way is to use interlocked compare-exchange in a loop:
(Pseudocode because I don't bother to look up the correct way to do an interlocked exchange in C#).
As you see, unless you have overriding efficiency concerns, using plain old mutexes is far simpler and more readable.
Edit: This assumes that
a
is a local variable or at least not subject to asynchronous writes. It both ofa
andb
can be modified behind your back, then there is no lock-free way of doing this update atomically. (Thanks to silev for pointing this out).亨宁是正确的。我将提供与 C# 相关的详细信息。该模式可以通过以下函数进行推广。
根据您的具体情况,我们可以定义一个像这样的 InterlockedGreaterThanExchange 函数。
Henning is correct. I will provide the details as they pertain to C#. The pattern can be generalized with the following function.
In your specific case we can define an
InterlockedGreaterThanExchange
function like this.不存在这样的原子操作来以真正的原子方式执行比较和赋值。在 C# 中,真正的原子操作可以是
Interlocked
操作,例如CompareExhenge()
和Exchange()
来交换两个整数值(32 位架构为 32 位,64 位架构为 64 位)。 -bit 用于 64 位处理器架构)。显然,简单的赋值
a = b
是两个操作 - 读和写。因此,不可能在一个原子步骤中进行比较+赋值...在任何其他语言/架构中是否可能,我的意思是真正的原子? ;)编辑:原始问题并不表明“a”是局部变量... uhhhggg 这样一个小修正...无论如何我都会保留我的答案,因为我相信真正的原子操作的本质,并且不是某种有野心成为原子的“技巧”
所以总结一下:
a
是本地,因此a
和b
都可能被其他线程访问There is no such atomic operation to execute both comparision and assignment in true atomic manner. In C# true atomic operations could be
Interlocked
operations likeCompareExchenge()
andExchange()
to exchange two integer values (32bit for 32bit architecture and 64-bit for 64 bit processor architecture).Obviously simple assignment
a = b
is a two operations - read and write. So there is no possibility to do comparision + assignment in one atomic step... Does it possible in any other language/architecture, I mean true atomic? ;)EDIT: Original question does not indicated that 'a' is local variable... uhhhggg such a small correction... any way I'll leave my answer as is because I believe in nature of true atomic operations and not in some kind of 'tricks' which has ambitions to be atomic
So to summarize:
a
is local, so botha
andb
potentially could be accessed by an other thread这些是我在阅读其他答案后想到的一些优化的“食谱”。与问题没有直接关系,但在此处添加,因为这是相关搜索的着陆点。试图将其保留为
a > b
或a >= b
以匹配原始问题。并保持它们的一般性,以免描述偏离其他相关问题。两者都可以包装到方法中。优化 - 单调
b
如果这是对
b
执行的唯一操作,否则b
为 >单调递增,您可以优化联锁分配和重试,其中a > > b == false
:如果
a>; b == false
任何重试后都不会是true
(b
只会变得更大),并且可以跳过交换,因为b< /code> 不会受到影响。
相关问题优化:松散限制
动作
signal()
每次局部变量a
(例如,系统时间样本)时只应调用一次自上次调用signal()
以来,已经增加了某个常数threshold >= 1
。这里,b
是与a
相比的阈值占位符,如果a >= b
则设置为a + Threshold
。只有“获胜”线程才应该调用signal()
。在这里,b 再次是单调的,但现在我们可以完全优化重试循环,因为我们只想知道本地线程是否在尊重阈值的同时与其他线程“赢得了比赛”代码>.此方法将有效地“阻止”任何其他线程在定义的阈值内发出信号。
节流注意事项
如果您需要“严格”节流(即“最小”
a
,其中a >= b
),则此选项将不起作用 - 因此“标题中的“宽松”。如果您只需要报告一系列紧密分组的a
中的最后一个,这也不起作用 - 可能称为 “去抖动”,相关但不同的问题。These are a couple of optimized "recipes" I came up with after reading other answers. Not directly related to the question, but adding here since this is where related searches landed. Tried to keep this to
a > b
ora >= b
to match the original question. And to keep them general so as not to bias the descriptions away from other related problems. Both could be wrapped into methods.Optimization - Monotonic
b
If this is the only operation that is being done to
b
orb
is otherwise monotonically increasing, you can optimize away the interlocked assignment and the retries wherea > b == false
:If
a > b == false
it won't betrue
after any retry (b
is only getting larger) and the exchange can be skipped sinceb
would be unaffected.Related problem optimization: Loose throttling
Action
signal()
should only be called once each time a local variablea
(e.g., a system time sample) has increased by some constantthreshold >= 1
since the last timesignal()
was called. Here,b
is a threshold placeholder compared toa
and set toa + threshold
ifa >= b
. Only the "winning" thread should callsignal()
.Here,
b
is again monotonic, but now we can optimize away the retry loop entirely since we only want to know if the local thread "won the race" with other threads while respectingthreshold
. This method will effectively "block" any other thread from signalling within the defined threshold.Throttling Caveats
This one will not work if you need a "strict" throttle--that is, the "smallest"
a
wherea >= b
--thus the "loose" in the title. This will also not work if you need to report only the last in a series of closely groupeda
s--what might be called "debouncing", related but distinct problem.