неизбежной «гонки» между истечением периода ожидания и изменением состояния предиката.
В некоторых реализациях, в частности мультипроцессорных, иногда возможно пробуждение сразу нескольких потоков, если сигнал об изменении состояния условной переменной генерируется одновременно на различных процессорах.
В общем случае при каждом завершении ожидания по условию поток должен оценивать значение предиката, связанного с ожиданием по условию, чтобы узнать, может ли он безопасно продолжать выполнение, ожидать или объявить тайм-аут. Возврат из состояния ожидания не означает, что соответствующий предикат имеет конкретное значение (ЛОЖЬ или ИСТИНА).
Поэтому рекомендуется ожидание по условию выражать в коде, эквивалентно
Семантика ожидания по времени
Абсолютное время было выбрано для задания параметра лимита времени по двум причинам. Во-первых, несмотря на то, что измерение относительного времени нетрудно реализовать в начале функции, для которой задается абсолютное время, с заданием абсолютного времени в начале функции, которая определяет относительное время, связано условие «гонок». Предположим, например, что функция clock_gettime() возвращает текущее время, а функция cond_relative_timed_wait () использует относительное время.
clock_gettime(CLOCK_REALTIME, &now)
reltime = sleep_til_this_absolute_time -now;
cond_relative_timed_wait (с, m, &reltime);
Если поток выгружается между первой и последней инструкциями, поток блокируется слишком надолго. Однако блокирование несущественно, если используется абсолютное время. Кроме того, абсолютное время не нужно пересчитывать, если оно используется в цикле несколько раз.
Для случаев, когда системные часы работают дискретно, можно предполагать, что реализации обработают любые ожидания по времени, истекающие в промежутке между дискретными состояниями, так, как если бы нужное время уже наступило.
Аннулирование потока и ожидание по условию
Ожидание по условию, синхронизированное или нет, является точкой отмены (аннулирования) потока. Другими словами, функции pthread_cond_wait () или pthread_cond_timedwait () представляют собой точки, в которых обнаружен необработанный запрос на отмену. Дело в том, что в этих точках возможно бесконечное ожидание, т.е. какое бы событие ни ожидалось, даже при совершенно корректной программе оно может никогда не произойти; например, входные данные, получения которых ожидает программа, могут быть никогда не отправлены. Сделав же ожидание по условию точкой отмены, поток можно безопасно аннулировать и выполнить соответствующие обработчики даже в случае, если программа «увязнет» в бесконечном ожидании.
Побочный эффект обработки запроса на от
Следовательно, поскольку в случае, когда запрос на отмену приходит во время ожидания, в отношении состояния блокировки должна быть выполнена определенная инструкция, при этом должно быть выбрано такое определение, которое сделает кодирование приложения наиболее удобным и свободным от ошибок.
При выполнении действий, связанных с получение
Быстродействие мьютексов и условных переменных
Предполагается, что мьютексы должны блокироваться только для нескольких инструкций. Такая практика почти автоматически вытекает из желания программистов избегать длинных последовательностей программных инструкций (которые способны снизить общую эффективность параллелизма).
При использовании мьютексов и условных переменных всегда пытаются обеспечить последовательность, которая считается обычным случаем: заблокировать мьютекс, получить доступ к общим данным и разблокировать мьютекс. Ожидание по условной переменной — относительно редкая ситуация. Например, при реализации блокировки чтения-записи коду, который получает блокировку чтения, обычно нужно лишь инкрементировать счетчик считывающих потоков (при взаимном исключении доступа). Вызывающий поток будет реально ожидать по условной переменной только тогда, когда уже существует активный записывающий поток. Поэтому эффективность операции синхронизации связана с «ценой» блокировки-разблокировки мьютекса, а не с ожиданием по условию. Обратите внимание на то, что в обычном случае переключения контекста не происходит.
Из вышесказанного отнюдь не следует, что эффективность ожидания по условию не важна. Поскольку существует потребность по крайней мере в одном переключении контекста на рандеву (взаимодействие между параллельными процессами), то эффективность ожидания по условию также важна. Цена ожидания по условной переменной должна быть намного меньше минимальной цены одного переключения контекста и времени, затрачиваемого на разблокировку и блокировку мьютекса.
Особенности мьютексов и условных переменных
Было предложено отделить захват и освобождение мьютекса от ожидания по условию. Но это предложение было отклонено, по причине «сборной природы» этой операции, которая в действительности упрощает реализации реального времени. Такие реализации могут незаметно перемещать высокоприоритетный поток между условной переменной и мьютексом, тем самым предотвращал излишние переключения контекстов и обеспечивал более детерминированное владение мьютексом при получении сигнала ожидающим потоком. Таким образом, вопросы равнодоступности и приоритетности могут быть решены непосредственно самой дисциплиной планирования. К тому же, широко распространенная операция ожидания по условию соответствует существующей практике.
Планирование поведения мьютексов и условных переменных
Примитивы (базовые элементы) синхронизации, которые могут противоречить используемой стратегии планирования путем установки «своего» правила упорядочения, считаются нежелательными. Выбор среди потоков, ожидающих освобождения мьютексов и условных переменных, происходит в порядке, который зависит именно от стратегии планирования, а не от какой-то другой дисциплины, устанавливающей некий фиксированный порядок (имеется в виду, например, FIFO-дисциплина или учет приоритетов). Таким образом, только стратегия планирования определяет, какой поток (потоки) будет запущен для продолжения работы.
Синхронизированное ожидание по условию
Функция pthread_cond_timedwait () позволяет приложению прервать ожидание наступления конкретного условия после истечения заданного интервала времени. Рассмотрим следующий пример.
(void) pthread_mutex_lock (&t. mn);
t.waiters++;
clock_gettime (CLOCK_REALTIME, &ts) ;