Параллельное и распределенное программирование на С++
Шрифт:
Побочный эффект обработки запроса на от м ену потока в случае, когда он заблокирован по условной переменной, состоит в повторном захвате мьютекса до вызова любого из обработчиков. Это позволяет гарантировать, что обработчик запроса на отмену выполняется в таком же статусе, который имеет критический код, расположенный до и после вызова функции ожидания по условию. Это правило также требуется соблюдать при взаимодействии с POSIX -потоками, написанными на таких языках программирования, как Ada или С++, причем здесь можно организовать отмену потоков с использованием встроенного в язык механизма исключительных ситуаций. Это правило гарантирует, что
Следовательно, поскольку в случае, когда запрос на отмену приходит во время ожидания, в отношении состояния блокировки должна быть выполнена определенная инструкция, при этом должно быть выбрано такое определение, которое сделает кодирование приложения наиболее удобным и свободным от ошибок.
При выполнении действий, связанных с получение м запроса на от м ену потока в то вре м я, когда он заблокирован по условной пере м енной, реализация требует гарантии, что поток не будет использовать ни один из условных сигналов, направленных на условную переменную, если существуют другие потоки, ожидающие сигнала по этой условной переменной. Соблюдение этого правила позволяет избежать условий взаимоблокировки, которые могут возникнуть в случае, если два независимых запроса (один действует в потоке, а другой связан с условной переменной) не были обработаны независимо.
Быстродействие мьютексов и условных переменных
Предполагается, что мьютексы должны блокироваться только для нескольких инструкций. Такая практика почти автоматически вытекает из желания программистов избегать длинных последовательностей программных инструкций (которые способны снизить общую эффективность параллелизма).
При использовании мьютексов и условных переменных всегда пытаются обеспечить последовательность, которая считается обычным случаем: заблокировать мьютекс, получить доступ к общим данным и разблокировать мьютекс. Ожидание по условной переменной — относительно редкая ситуация. Например, при реализации блокировки чтения-записи коду, который получает блокировку чтения, обычно нужно лишь инкрементировать счетчик считывающих потоков (при взаимном исключении доступа). Вызывающий поток будет реально ожидать по условной переменной только тогда, когда уже существует активный записывающий поток. Поэтому эффективность операции синхронизации связана с «ценой» блокировки-разблокировки мьютекса, а не с ожиданием по условию. Обратите внимание на то, что в обычном случае переключения контекста не происходит.
Из вышесказанного отнюдь не следует, что эффективность ожидания по условию не важна. Поскольку существует потребность по крайней мере в одном переключении контекста на рандеву (взаимодействие между параллельными процессами), то эффективность ожидания по условию также важна. Цена ожидания по условной переменной должна быть намного меньше минимальной цены одного переключения контекста и времени, затрачиваемого на разблокировку и блокировку мьютекса.
Особенности мьютексов и условных переменных
Было предложено отделить захват и освобождение мьютекса от ожидания по условию. Но это предложение было отклонено, по
Планирование поведения мьютексов и условных переменных
Примитивы (базовые элементы) синхронизации, которые могут противоречить используемой стратегии планирования путем установки «своего» правила упорядочения, считаются нежелательными. Выбор среди потоков, ожидающих освобождения мьютексов и условных переменных, происходит в порядке, который зависит именно от стратегии планирования, а не от какой-то другой дисциплины, устанавливающей некий фиксированный порядок (имеется в виду, например, FIFO-дисциплина или учет приоритетов). Таким образом, только стратегия планирования определяет, какой поток (потоки) будет запущен для продолжения работы.
Синхронизированное ожидание по условию
Функция pthread_cond_timedwait позволяет приложению прервать ожидание наступления конкретного условия после истечения заданного интервала времени. Рассмотрим следующий пример.
(void) pthread_mutex_lock (&t. mn);
t.waiters++;
clock_gettime (CLOCK_REALTIME, &ts) ;
ts.tv_sec += 5;
rc = 0;
while (! mypredicate (&t) && rc == 0)
rc = pthread_cond_timedwait (&t.cond, &t.mn, &ts);
t.waiters--;
if (rc == 0) setmystate (&t);
(void) pthread_mutex_unlock (&t.mn);
Абсолютный параметр времени ожидания позволяет не пересчитывать его значение каждый раз, когда программа проверяет значение предиката блокирования. Если бы время ожидания было задано относительной величиной, соответствующий пересчет пришлось бы делать перед каждым вызовом функции. Это было бы особенно трудно сделать, поскольку такому колу пришлось бы учитывать возможность дополнительных запусков вследствие дополнительной сигнализации по условной переменной, которые могут происходить до того, как предикат станет истинным или истечет время ожидания.
Будущие направления
Отсутствуют.
Смотри также
pthread_cond_signal , pthread_cond_broadcast , том Base Definitions стандарта IEEE Std 1003.1-2001, <pthread.h>.
Последовательность внесения изменений
Функции впервые реализованы в выпуске Issue 5. Включены для согласования с расширением POSIX Threads Extension.
Issue 6
Функции pthread_cond_timedwait и pthread_cond_wait от м ечены как часть опции Threads.
К описанию прототипа функции pthread_cond_wait был приложен список опечаток Open Group Corrigendum U021/9.
Для согласования со стандартом IEEE Std 1003.1j-2000 раздел «Описание» был отредактирован путем добавления семантики для опции Clock Selection.
В раздел «Ошибки» внесен еще один код ошибки [EPERM] в ответ на включение интерпретации IEEE PASC Interpretation 1003.1с #28.
В целях согласования со стандартом ISO/IEC 9899: 1999 в прототипы функций pthread_cond_timedwait и pthread_cond_wait было добавлено ключевое слово restrict.