patterncsharpMinor
Try a speculative, concurrent, lock free, atomic update until abort condition matches
Viewed 0 times
matchesupdateconditionuntilfreespeculativeabortatomicconcurrenttry
Problem
Please let me know if you see any performance improvements, bugs, or anything you'd change and why.
Can be used like this
What I'm really trying to accomplish is the fastest thread safe version of Interlocked.Increment that will stop incrementing at a max value and I will have some way of detecting it stopped incrementing.
public static bool TrySpeculativeUpdate(ref int field, out int result,
Func update, Func shouldAbort)
{
SpinWait spinWait = new SpinWait();
while (true)
{
int snapshot = field;
if (shouldAbort(field))
{
result = 0;
return false;
}
else
{
int calc = update(snapshot);
if (Interlocked.CompareExchange(ref field, calc, snapshot) == snapshot)
{
result = calc;
return true;
}
}
spinWait.SpinOnce();
}
}Can be used like this
private bool TryIncreaseCapacity(out int newCapacity)
{
return TrySpeculativeUpdate(ref _currentCapacity, out newCapacity,
(currentCapacity) => currentCapacity + 1,
(currentCapacity) => currentCapacity == _maxCapacity);
}
if (this.TryIncreaseCapacity(out newCapacity))
{
...
}
else
{
...
}What I'm really trying to accomplish is the fastest thread safe version of Interlocked.Increment that will stop incrementing at a max value and I will have some way of detecting it stopped incrementing.
Solution
I'm not sure I like the method's signature:
It's probably just me, but I like pushing
I'd use
That's all I could see. The naming looks about right, but I don't write enough multithreaded code to know for a fact whether this code is optimal or not - it does look good though, I don't see how nesting could be reduced, other than by extacting a tiny little specialized function responsible for this part:
But that clearly would be overkill IMO.
public static bool TrySpeculativeUpdate(ref int, out int, Func, Func)It's probably just me, but I like pushing
ref and out parameters to the end of the parameters list, so I'd write it like this:public static bool TrySpeculativeUpdate(Func, Func, ref int, out int)I'd use
var to ease reading, and FWIW it might be clearer to pass snapshot instead of field to shouldAbort:public static bool TrySpeculativeUpdate(Func update, Func shouldAbort, ref int field, out int result)
{
var spinWait = new SpinWait();
while (true)
{
var snapshot = field;
if (shouldAbort(snapshot))
{
result = 0;
return false;
}
else
{
var calc = update(snapshot);
if (Interlocked.CompareExchange(ref field, calc, snapshot) == snapshot)
{
result = calc;
return true;
}
}
spinWait.SpinOnce();
}
}That's all I could see. The naming looks about right, but I don't write enough multithreaded code to know for a fact whether this code is optimal or not - it does look good though, I don't see how nesting could be reduced, other than by extacting a tiny little specialized function responsible for this part:
if (Interlocked.CompareExchange(ref field, calc, snapshot) == snapshot)
{
result = calc;
return true;
}But that clearly would be overkill IMO.
Code Snippets
public static bool TrySpeculativeUpdate(ref int, out int, Func<int, int>, Func<int, bool>)public static bool TrySpeculativeUpdate(Func<int, int>, Func<int, bool>, ref int, out int)public static bool TrySpeculativeUpdate(Func<int, int> update, Func<int, bool> shouldAbort, ref int field, out int result)
{
var spinWait = new SpinWait();
while (true)
{
var snapshot = field;
if (shouldAbort(snapshot))
{
result = 0;
return false;
}
else
{
var calc = update(snapshot);
if (Interlocked.CompareExchange(ref field, calc, snapshot) == snapshot)
{
result = calc;
return true;
}
}
spinWait.SpinOnce();
}
}if (Interlocked.CompareExchange(ref field, calc, snapshot) == snapshot)
{
result = calc;
return true;
}Context
StackExchange Code Review Q#51725, answer score: 2
Revisions (0)
No revisions yet.