Использование Mutex<T> для Синхронизации Доступа к Общему Ресурсу
Когда вам нужно получить доступ к общему ресурсу, вы можете использовать оператор lock или примитив синхронизации, такой как System.Threading.Mutex, для синхронизации доступа.
Однако в сложном коде его легко забыть:
var obj = new object();
var value = 42;
lock (obj)
{
// Надо убедиться, что lock используется везде, где происходит доступ к ресурсу
Console.WriteLine(value);
}
// ⚠️ Здесь доступ получен без блокировки
value = 43;
Можно сделать это более явным и менее подверженным ошибкам, создав класс Mutex<T>, который инкапсулирует общий ресурс и примитив синхронизации:
var m = new Mutex<int>(42);
using (var scope = m.Acquire())
{
// доступ к ресурсу
Console.WriteLine(scope.Value);
// изменение ресурса
scope.Value = 43;
}
// ✔️ Вы не можете использовать общий ресурс вне области мьютекса
Вот реализация класса Mutex<T> и его области MutexScope<T>:
sealed class Mutex<T>
{
internal T _value;
private readonly Lock _lock = new();
public Mutex() { _value = default!; }
public Mutex(T initialValue)
=> _value = initialValue;
public MutexScope<T> Acquire()
{
_lock.Enter();
return new MutexScope<T>(this);
}
internal void Release()
=> _lock.Exit();
}
sealed class MutexScope<T>
: IDisposable
{
private readonly Mutex<T> mutex;
private bool disposed;
internal MutexScope(Mutex<T> mutex)
{
this.mutex = mutex;
}
public ref T Value
{
get
{
ObjectDisposedException
.ThrowIf(disposed, this);
return ref mutex._value!;
}
}
public void Dispose()
{
mutex.Release();
disposed = true;
}
}
Источник: https://www.meziantou.net/using-mutex-t-to-synchronize-access-to-a-shared-resource.htm