Below is an implementation of an interlocked method based on Interlocked.CompareExchange
.
Is it advisable for this code to use a SpinWait
spin before reiterating?
public static bool AddIfLessThan(ref int location, int value, int comparison)
{
int currentValue;
do
{
currentValue = location; // Read the current value
if (currentValue >= comparison) return false; // If "less than comparison" is NOT satisfied, return false
}
// Set to currentValue+value, iff still on currentValue; reiterate if not assigned
while (Interlocked.CompareExchange(ref location, currentValue + value, currentValue) != currentValue);
return true; // Assigned, so return true
}
I have seen SpinWait
used in this scenario, but my theory is that it should be unnecessary. After all, the loop only contains a handful of instructions, and there is always one thread making progress.
Say that two threads are racing to perform this method, and the first thread succeeds right away, whereas the second thread initially makes no change and has to reiterate. With no other contenders, is it at all possible for the second thread to fail on its second attempt?
If the example's second thread cannot fail on the second attempt, then what might we gain with a SpinWait
? Shaving off a few cycles in the unlikely event that a hundred threads are racing to perform the method?
increment
(3 Assembly instructions) can get race conditioned and return a false value – RadferdSpinOnce
to prevent a single-threaded OS from potentially being starved. See #37799881 – JohstInterlocked
. For clarification, I am only interested in whether or not aSpinWait
is meaningful, for example to meaningfully save CPU cycles or (thanks @MatthewWatson!) prevent a single-threaded OS from being starved. – RackrentSpinWait
will not even reduce power consumption, as the same number of attempts will be performed anyway! (With two threads, that is one attempt for the first and two for the second thread.) – RackrentspinWait.SpinOnce()
solve it? – Garethref location
.Interlocked.CompareExchange
lets only one thread do that at a time. "Losing" threads loop vigorously, andSpinWait
can make that less vigorously. The question is whether that adds practical value in this scenario, as the operation is so simple and fast (i.e. threads succeed in such rapid succession that spinning may be overkill). – Rackrentref location
(the contended place in memory), which must only be written to by one thread at a time. As the question indicates, my theory is that looping vigorously is fine, and I'm trying to make sure that theory is correct. – Rackrent