Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Semaphore в C#
Semaphore — это синхронизационный примитив, который ограничивает количество потоков, имеющих доступ к ресурсу. Это более гибкая альтернатива Lock для управления доступом к пулу ресурсов.
Как работает Semaphore
// Максимум 3 потока могут одновременно использовать ресурс
var semaphore = new Semaphore(3, 3);
for (int i = 0; i < 10; i++)
{
int taskId = i;
Task.Run(() =>
{
semaphore.WaitOne(); // Ждем, пока счетчик > 0
try
{
Console.WriteLine($"Task {taskId} started");
Thread.Sleep(1000);
Console.WriteLine($"Task {taskId} finished");
}
finally
{
semaphore.Release(); // Увеличиваем счетчик
}
});
}
Binary Semaphore vs Counting Semaphore
Binary Semaphore (0 или 1) — как Lock:
var binary = new Semaphore(1, 1); // 1 поток
Counting Semaphore (n ресурсов):
var counting = new Semaphore(5, 5); // 5 потоков
Named Semaphore (inter-process)
// Разные приложения могут синхронизироваться
var named = new Semaphore(2, 2, "MyAppResource");
SemaphoreSlim для асинхронного кода
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(3); // 3 одновременно
public async Task ProcessAsync(int id)
{
await _semaphore.WaitAsync(); // Асинхронное ожидание
try
{
Console.WriteLine($"Processing {id}");
await Task.Delay(1000);
}
finally
{
_semaphore.Release();
}
}
// Использование
var tasks = Enumerable.Range(1, 10)
.Select(i => ProcessAsync(i))
.ToArray();
await Task.WhenAll(tasks);
Пример: Пул соединений
public class ConnectionPool
{
private readonly SemaphoreSlim _available;
private readonly List<DbConnection> _connections;
public ConnectionPool(int size)
{
_available = new SemaphoreSlim(size);
_connections = new List<DbConnection>(size);
for (int i = 0; i < size; i++)
_connections.Add(new DbConnection());
}
public async Task<DbConnection> GetConnectionAsync()
{
await _available.WaitAsync();
lock (_connections)
{
return _connections[0];
}
}
public void ReturnConnection(DbConnection conn)
{
_available.Release();
}
}
Semaphore vs Lock
| Аспект | Semaphore | Lock |
|---|---|---|
| Количество потоков | Много (N) | 1 |
| Асинхронность | SemaphoreSlim | Нет |
| Inter-process | Да (Named) | Нет |
| Сложность | Выше | Ниже |
| Использование | Пулы ресурсов | Критические секции |
Проблемы и решения
Deadlock при неправильном Release:
var sem = new Semaphore(1, 1);
sem.WaitOne();
// Забыли Release() — deadlock!
// sem.Release(); // ← ОБЯЗАТЕЛЬНО!
Правильно с try-finally:
var sem = new Semaphore(2, 2);
sem.WaitOne();
try
{
// Работа с ресурсом
}
finally
{
sem.Release(); // Гарантированно вызовется
}
Практические применения
- Пулы соединений — ограничение одновременных подключений
- Rate limiting — ограничение запросов в секунду
- Управление ресурсами — ограничение потребления памяти
- Обработка очередей — контроль параллельных задач
Semaphore — это мощный инструмент для управления доступом к ограниченным ресурсам в многопоточных приложениях.