Реферат: Синхронизация потоков
void RequestReader( NEWSWMRG* p ) {
// дождаться разрешения для читателя — убедиться, что нет писателей
// для этого можно захватить объект ЕСТЬ_ПИСАТЕЛИ и сразу освободить его
// захват пройдет только тогда, когда писателей нет.
Захватить объект ЕСТЬ_ПИСАТЕЛИ;
// реально надо не только убедиться в отсутствии писателей, но и
// увеличить счетчик и при необходимости сбросить событие НЕТ_ЧИТАТЕЛЕЙ
if ( ЧИСЛО_ЧИТАТЕЛЕЙ == 0 ) Сбросить событие НЕТ_ЧИТАТЕЛЕЙ в занятое;
ЧИСЛО_ЧИТАТЕЛЕЙ++;
// а вот теперь можно смело освобождать объект ЕСТЬ_ПИСАТЕЛИ — во время
// работы читателя достаточно иметь сброшенное событие НЕТ_ЧИТАТЕЛЕЙ Освободить объект ЕСТЬ_ПИСАТЕЛИ;
}
void ReleaseReader( NEWSWMRG* p ) {
// после считывания данных уменьшаем счетчик и разрешаем доступ писателям
// при достижении нулевого значения счетчика.
--ЧИСЛО_ЧИТАТЕЛЕЙ;
if ( ЧИСЛО_ЧИТАТЕЛЕЙ == 0 ) Установить событие НЕТ_ЧИТАТЕЛЕЙ в свободное;
}
Естественно, это еще не рабочая схема, а только намек на нее. Полностью обсудим некоторые особенности при рассмотрении функций Win32 API. На первый взгляд виден небольшой “прокол” — в функции ReleaseReader счетчик сначала уменьшается, а только потом происходит проверка его значения и установка события при необходимости. Однако возможен (хотя и очень маловероятен) случай, когда поток будет прерван для выполнения операций другими потоками где–то между уменьшением счетчика и установкой события. В это время другие потоки могут изменить значение счетчика и событие будет установлено тогда, когда этого делать уже не следует.
Выйти из этой ситуации можно разными путями — либо добавлением еще одного объекта исключительного владения или критической секции для упорядочивания операций со счетчиком, либо другими способами. Для разбирательства с этими альтернативными способами следует рассмотреть синхронизацию с группой объектов.
[1] Возможны такие объекты, хотя это не типичный случай, когда читатели не конфликтуют с писателями. Тогда в ситуациях 2 и 3 следует разрешать доступ.
[2] В Win32 API существуют специальные механизмы, позволяющие возобновлять исполнение только одного потока при освобожении события. Однако, по сравнению с другими операционными системами, скажем OS/2, такое поведение события нетипично.