We have following class:
class ProcessStore
{
ConcurrentDictionary<int, MyDisposableClass> _processes = new();
bool _disposed;
void Store(int Id)
{
if(_disposed) { throw; }
var mdc = new MyDisposableClass();
_requests.Add(Id, mdc);
}
void Dispose()
{
if(_disposed)
{
return;
}
_disposed = true;
foreach(var process in _processes)
{
process.Dispose();
}
}
}
Multiple threads may Store processes, and another thread will dispose it (but only single thread will dispose at time). This is effectively producer-consumer problem.
How can we make this class thread-safe? By thread-safe I mean that disposing instance disposes all Store
requests and throws on new attempts. Simple answer is using locks, but I wonder if it's possible to do it correctly lock-free. I have following idea:
class ProcessStore
{
ConcurrentDictionary<int, MyDisposableClass> _processes = new();
volatile bool _disposed;
void Store(int Id)
{
if(_disposed) { throw; }
var mdc= new MyDisposableClass();
_requests.Add(Id, mdc);
if(_disposed) { _requests.Remove(mdc); mdc.Dispose(); throw; }
}
void Dispose()
{
if(_disposed)
{
return;
}
_disposed = true;
foreach(var process in _processes)
{
process.Dispose();
}
}
}
So two new things are volatile
on disposal, which ensures all threads see latest state, and additional check after adding to _requests
dictionary, which eventually undoes it if object was disposed in meanwhile.
So if class was disposed after first dispose check, but before adding to dictionary, thread running Store
thread will see that operation failed after adding, and will reverse it.
ConcurrentDictionary
doesn't mean you're "lock-free". It just means you haven't written any locks. (The locks are inside the dictionary implementation.)