I've been following Pluralsight course, authored by Simon Robinson on Concurrent Collections.
He uses AddOrUpdate
in the following way in order to make it thread-safe:
public bool TrySellShirt(string code)
{
bool success = false;
_stock.AddOrUpdate(code,
(itemname) => { success = false; return 0; },
(itemName, oldValue) =>
{
if (oldValue == 0)
{
success = false;
return 0;
}
else
{
success = true;
return oldValue - 1;
}
});
if (success)
Interlocked.Increment(ref _totalQuantitySold);
return success;
}
So, I'm aware that AddOrUpdate isn't entirely atomic, as it says in the docs: " the addValueFactory and updateValueFactory delegates are called outside the locks to avoid the problems that can arise from executing unknown code under a lock. "
That to me is clear. What isn't clear is what's the point of setting success
to false
within the delegates. AddValueFactory
argument is deliberately used as lambda so success = false
can be set, rather than just returning 0. I somewhat understand/think that if the method/lambda is interrupted by another thread (and it can be interrupted because it's called outside of the lock), it will attempt to repeat itself and so we should set state of any corresponding values to their initial value to cleanly engage new iteration, hence setting success = false;
.
Also from the docs: If you call AddOrUpdate simultaneously on different threads, addValueFactory may be called multiple times, but its key/value pair might not be added to the dictionary for every call.
If that's the case, I've been checking source code of AddOrUpdate
on source.dot.net, I can't see any locks being used anywhere, I can see TryAddInternal
and TryUpdateInternal
.
Regardless, aforeposted method works but I don't understand why it works, and as soon as I remove seemingly unnecessary success = false
assignments it doesn't work, there is mismatch. So I'm curious what makes these delegates repeat themselves after failure?
Questions I have are:
1. Is it safe to use AddOrUpdate
as shown or should I just lock everything and forget about it?
2. What makes delegates repeat themselves after being interrupted? Does it have anything to do with 'Compare-and-swap'? (most curious about this one);
3. Are there any topics/concepts you would have me check out to better understand thread-safe environment?