Мотивация
началась со знакомства с моделью многопоточного (процессного) программирования, и я узнал примитивы синхронизации, связанные с семафором (Семафором). Я не знаю, почему в .Net Framework нет соответствующего материала. Ужасно то, что я использовал ее для реализации множества проверенных временем кодов на C++. Чтобы не дать революционным мученикам принять лекарство и пролить кровь напрасно, мне пришлось родить одного самому.
Что такое семафор?
Если вы уже понимаете концепцию семафора, пропустите этот раздел.
Семафор — это средство, используемое в многопоточной среде. Он отвечает за координацию различных потоков, чтобы гарантировать, что они могут правильно и разумно использовать общедоступные ресурсы.
Давайте посмотрим, как работает парковка. Для простоты предположим, что на парковке всего три парковочных места, и все три парковочных места вначале пустуют. Это если одновременно приезжают пять машин, и привратник беспрепятственно пропускает три из них, а затем ставит блокировку, остальные машины должны ждать на въезде, а последующие машины тоже должны будут ждать на въезде. вход. В это время со стоянки выехала машина. После того, как привратник узнал об этом, он открыл автомобильный шлагбаум и вставил одну машину. Если выехали еще две машины, он мог поставить еще две машины и так далее.
В этой системе парковок парковочные места являются общественными ресурсами, каждая машина подобна нити, а привратник действует как семафор.
Кроме того, характеристики семафора таковы: семафор представляет собой неотрицательное целое число (количество парковочных мест), и все потоки (транспортные средства), проходящие через него, уменьшают целое число на единицу (при его передаче, конечно, используются ресурсы ). Когда целочисленное значение равно нулю, все потоки, пытающиеся передать его, будут находиться в состоянии ожидания. Мы определяем две операции над семафором: Wait и Release. Когда поток вызывает операцию Wait, он либо передает семафор, а затем уменьшает его на единицу, либо ждет, пока семафор не станет больше единицы или не истечет время ожидания. Release фактически выполняет операцию добавления к семафору, что соответствует выезду автомобиля со стоянки. Причина, по которой эта операция называется «освобождением», заключается в том, что операция добавления фактически освобождает ресурсы, охраняемые семафором.
выполнить
Как мы все знаем, средства синхронизации потоков, предоставляемые в библиотеке классов .Net Framework, включают в себя:
Monitor, AutoResetEvent, ManualResetEvent, Mutex, ReadWriteLock и InterLock. Среди них AutoResetEvent, ManualResetEvent и Mutex являются производными от WaitHandler и фактически инкапсулируют объекты ядра, предоставляемые операционной системой. Другие должны быть собственными для виртуальной машины .Net. Очевидно, что возможности объектов ядра операционной системы менее эффективны в использовании. Однако эффективность не является проблемой, которую мы должны здесь рассматривать. Мы будем использовать два монитора и объект ManualResetEvent для имитации семафора.
Код выглядит следующим образом:
Семафор публичного класса
{
частный ManualResetEvent waitEvent = новый ManualResetEvent (false);
частный объект syncObjWait = новый объект();
Private int maxCount = 1 //Максимальное количество ресурсов
Private int currentCount = 0 //Текущее количество ресурсов
public Semaphore();
{
}
публичный семафор (int maxCount)
{
this.maxCount = maxCount;
}
public bool Wait()
{
lock( syncObjWait ) //Только один поток может ввести следующий код
{
bool waitResult = this.waitEvent.WaitOne(); //Количество ожидающих здесь ресурсов больше нуля
если (ожиданиеРезультат)
{
заблокировать (это)
{
если (текущийCount > 0)
{
текущийCount--;
если (текущийCount == 0)
{
это.waitEvent.Reset();
}
}
еще
{
System.Diagnostics.Debug.Assert( false, «Семафор не допускает текущего счетчика < 0»);
}
}
}
вернуть результат ожидания;
}
}
/**//// <сводка>
/// Операция ожидания, позволяющая вернуть тайм-аут
/// </сводка>
/// <param name="milliсекундыTimeout"></param>
/// <возвращается></возвращается>
public bool Wait (int milliсекундыTimeout)
{
lock( syncObjWait ) // Монитор гарантирует, что код класса области находится в критическом разделе
{
bool waitResult = this.waitEvent.WaitOne (миллисекундыTimeout, false);
если (ожиданиеРезультат)
{
заблокировать (это)
{
если (текущийCount > 0)
{
текущийCount--;
если (текущийCount == 0)
{
это.waitEvent.Reset();
}
}
еще
{
System.Diagnostics.Debug.Assert( false, «Семафор не допускает текущего счетчика < 0»);
}
}
}
вернуть результат ожидания;
}
}
общественный логический выпуск()
{
lock(this) // Монитор гарантирует, что код класса области находится в критическом разделе
{
текущийCount++;
если (currentCount > this.maxCount)
{
currentCount = this.maxCount;
вернуть ложь;
}
this.waitEvent.Set(); //Разрешаем потоку, вызывающему Wait, войти
}
вернуть истину;
}
}