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
or a >= 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
or b
is otherwise monotonically increasing, you can optimize away the interlocked assignment and the retries where a > b == false
:
int initial;
do
{
initial = b;
}
while ((a > initial) && Interlocked.CompareExchange(ref b, a, initial) != initial);
If a > b == false
it won't be true
after any retry (b
is only getting larger) and the exchange can be skipped since b
would be unaffected.
Related problem optimization: Loose throttling
Action signal()
should only be called once each time a local variable a
(e.g., a system time sample) has increased by some constant threshold >= 1
since the last time signal()
was called. Here, b
is a threshold placeholder compared to a
and set to a + threshold
if a >= b
. Only the "winning" thread should call signal()
.
var initial = b;
if ((a > initial) && Interlocked.CompareExchange(ref b, a + threshold, initial) == initial)
{
signal();
}
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 respecting threshold
. 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
where a >= 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 grouped a
s--what might be called "debouncing", related but distinct problem.