Ответ
В C# для синхронизации доступа к общим ресурсам из нескольких потоков используется ряд примитивов. Выбор зависит от сценария:
-
lock(ключевое слово, обертка надMonitor): Стандартный выбор для синхронизации в рамках одного процесса.private readonly object _syncRoot = new object(); public void ModifySharedResource() { lock (_syncRoot) { // Критическая секция. Только один поток выполняет этот блок. sharedCounter++; } } -
Mutex(мьютекс): Подходит для межпроцессной синхронизации (например, чтобы гарантировать запуск только одного экземпляра приложения).using var mutex = new Mutex(false, "Global\MyAppSingletonMutex"); if (!mutex.WaitOne(TimeSpan.FromSeconds(5))) { Console.WriteLine("Другой экземпляр приложения уже запущен."); return; } try { /* Работа приложения */ } finally { mutex.ReleaseMutex(); } -
SemaphoreSlim/Semaphore: Ограничивают количество потоков, которые могут одновременно войти в критическую секцию.SemaphoreSlimлегче и рекомендуется для внутрипроцессной работы.private readonly SemaphoreSlim _pool = new SemaphoreSlim(2, 2); // Максимум 2 потока public async Task AccessDatabaseAsync() { await _pool.WaitAsync(); try { /* Ограниченный доступ к ресурсу (напр., соединению с БД) */ } finally { _pool.Release(); } } -
ReaderWriterLockSlim: Оптимизирован для сценариев, где чтение происходит часто, а запись редко. Позволяет множественное чтение, но эксклюзивную запись.private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); public string ReadData() { _rwLock.EnterReadLock(); try { return cachedData; } finally { _rwLock.ExitReadLock(); } } public void UpdateData(string newData) { _rwLock.EnterWriteLock(); try { cachedData = newData; } finally { _rwLock.ExitWriteLock(); } }
Общая рекомендация: Для простых случаев используйте lock. Для асинхронного кода — SemaphoreSlim. Для межпроцессного взаимодействия — Mutex. Для оптимизации read-heavy нагрузок — ReaderWriterLockSlim.