Блокировки по чтению/записи

Блокировки по чтению/записи (reader/writer locks) (или более точное назва­ние "блокировки на множественное чтение и однократную запись") исполь­зуются в тех случаях, когда доступ к структуре данных должен определяться по следующей схеме: чтение данных выполняет множество потоков, запись — не более одного потока.

Блокировка по чтению/записи (pthread_rwlock_rdlock()) предоставляет доступ по чтению всем потокам, которые его запрашивают. Однако если поток за­прашивает блокировку по записи (pthread_rwlock_wrlock()), запрос отклоня­ется до тех пор, пока все потоки, выполняющие чтение, не снимут свои блокировки по чтению (pthread_rwlock_unlock()).

Множество потоков, выполняющих запись, выстраиваются в очередь (в по­рядке своих приоритетов), ожидая возможности выполнить операцию запи­си в защищенную структуру данных. Все блокированные потоки, выпол­няющие запись, запускаются до того, как читающие потоки снова получат разрешение на доступ к данным. Приоритеты читающих потоков не учиты­ваются.

Существуют специальные вызовы, которые позволяют потоку тестировать возможность доступа к необходимой блокировке, оставаясь в активном со­стоянии (pthread rwlockt ryrdlock() и ptfiread_rwlock_trywrlock()). Эти вызовы возвращают код завершения, сообщающий о возможности или невозможно­сти установки блокировки.

Реализация блокировок по чтению/записи происходит не в ядре, а посред­ством мьютексов и условных переменных, предоставляемых ядром.

 

Семафоры

Еще одним средством синхронизации являются семафоры (semaphores), кото­рые позволяют потокам увеличивать (с помощью функции sem_post()) или уменьшать (с помощью функции sem_wait()) значение счетчика на семафоре для управления блокировкой потока (операции "post" и "wait" соответственно).

При вызове функции sem_wait() поток не блокируется, если счетчик имел положительное значение. При неположительном значении счетчика поток блокируется до тех пор, пока какой-либо другой поток не увеличит значе­ние счетчика. Увеличение значения счетчика может выполняться несколько раз подряд, что позволяет уменьшать значение счетчика, не вызывая блоки­ровки потоков.

Существенным отличием семафоров от других примитивов синхронизации является то, что семафоры безопасны для применения в асинхронной среде ("async safe") и могут управляться обработчиками сигналов. Семафоры как раз подходят для тех случаев, когда требуется пробудить поток с помощью обработчика сигнала.

Другим полезным свойством семафоров является то, что они были опреде­лены для работы между процессами. Хотя мьютексы в QNX Neutrino тоже работают между процессами, стандарты POSIX рассматривают эту возмож­ность как дополнительную функцию, которая может оказаться не переноси­мой между системами.

Полезной разновидностью семафоров является служба именованных семафо­ров (named semaphore service). Эта служба использует администратор ресур­сов и позволяет применять семафоры между процессами, выполняемыми на разных машинах внутри сети.

Поскольку семафоры, как и условные переменные, могут в штатном поряд­ке возвращать ненулевое значение из-за ложного пробуждения, для их кор­ректной работы требуется использование цикла:

while (sem wait(&s) && errno == EINTR) {

do_nothing();

}

do_critical_region();/* Значение семафора уменьшилось. */

 

Синхронизация с помощью алгоритма планирования

Применение алгоритма FIFO-планирования стандарта POSIX в системе без симметричной многопроцессорной обработки предотвращает выполнение критической секции кода одновременно несколькими потоками с одинако­вым приоритетом. Алгоритм FIFO-планирования предписывает, что все по­токи, запланированные к выполнению по этому алгоритму и имеющие оди­наковый приоритет, выполняются до тех пор, пока они самостоятельно не освободят процессор для другого потока.

Такое "освобождение" процессора также может произойти в случае, когда поток блокируется в результате обращения к другому процессу за сервисом или при получении сигнала. Поэтому критическая секция кода должна быть тщательно проработана и документирована для того, чтобы последующее об­служивание этого кода не приводило к нарушению данного условия. Кроме того, потоки с более высоким приоритетом в том (или любом другом) процессе все же могут вытеснять потоки, выполняемые по алгоритму FIFO-планирования. Поэтому все потоки, которые могут "столкнуться" между со­бой внутри критической секции кода, должны планироваться по алгоритму FIFO с одинаковым приоритетом. При таком условии потоки могут обра­щаться к этой разделяемой памяти без необходимости делать предваритель­ный явный запрос на синхронизацию.

Метод монопольного доступа неприменим в многопроцессорных системах, по­скольку в таких системах несколько процессоров могут одновременно испол­нить код, который в однопроцессорной машине был бы запланирован на после­довательное исполнение.

 








Дата добавления: 2017-01-29; просмотров: 1158;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.006 сек.