Параллельное и распределенное программирование на С++ - Хьюз Камерон
Шрифт:
Интервал:
Закладка:
Быстродействие мьютексов и условных переменных
Предполагается, что мьютексы должны блокироваться только для нескольких инструкций. Такая практика почти автоматически вытекает из желания программистов избегать длинных последовательностей программных инструкций (которые способны снизить общую эффективность параллелизма).
При использовании мьютексов и условных переменных всегда пытаются обеспечить последовательность, которая считается обычным случаем: заблокировать мьютекс, получить доступ к общим данным и разблокировать мьютекс. Ожидание по условной переменной — относительно редкая ситуация. Например, при реализации блокировки чтения-записи коду, который получает блокировку чтения, обычно нужно лишь инкрементировать счетчик считывающих потоков (при взаимном исключении доступа). Вызывающий поток будет реально ожидать по условной переменной только тогда, когда уже существует активный записывающий поток. Поэтому эффективность операции синхронизации связана с «ценой» блокировки-разблокировки мьютекса, а не с ожиданием по условию. Обратите внимание на то, что в обычном случае переключения контекста не происходит.
Из вышесказанного отнюдь не следует, что эффективность ожидания по условию не важна. Поскольку существует потребность по крайней мере в одном переключении контекста на рандеву (взаимодействие между параллельными процессами), то эффективность ожидания по условию также важна. Цена ожидания по условной переменной должна быть намного меньше минимальной цены одного переключения контекста и времени, затрачиваемого на разблокировку и блокировку мьютекса.
Особенности мьютексов и условных переменных
Было предложено отделить захват и освобождение мьютекса от ожидания по условию. Но это предложение было отклонено, по причине «сборной природы» этой операции, которая в действительности упрощает реализации реального времени. Такие реализации могут незаметно перемещать высокоприоритетный поток между условной переменной и мьютексом, тем самым предотвращал излишние переключения контекстов и обеспечивал более детерминированное владение мьютексом при получении сигнала ожидающим потоком. Таким образом, вопросы равнодоступности и приоритетности могут быть решены непосредственно самой дисциплиной планирования. К тому же, широко распространенная операция ожидания по условию соответствует существующей практике.
Планирование поведения мьютексов и условных переменных
Примитивы (базовые элементы) синхронизации, которые могут противоречить используемой стратегии планирования путем установки «своего» правила упорядочения, считаются нежелательными. Выбор среди потоков, ожидающих освобождения мьютексов и условных переменных, происходит в порядке, который зависит именно от стратегии планирования, а не от какой-то другой дисциплины, устанавливающей некий фиксированный порядок (имеется в виду, например, 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.
pthread_condattr_destroy, pthread_condattr_init
Имя
pthread_condattr_destroy, pthread_condattr_init — функции разрушения и инициализации объекта атрибутов условной пере м енной.
Синопсис
THR
#include <pthread.h>
int pthread_condattr_destroy (pthread_condattr_t *attr);
int pthread_condattr_init (pthread_condattr_t *attr);
Описание
Функция pthread_condattr_destroy() используется для разрушения объекта атрибутов условной переменной, в результате чего он становится неинициализированным. В конкретной реализации функция pthread_condattr_destroy() может устанавливать объект, адресуемый параметром attr , равным недействительному значению. Разрушенный объект атрибутов attr можно снова инициализировать с помощью функции pthread_condattr_init (); результаты ссылки на этот объект после его разрушения не определены.
Функция pthread_condattr_init () предназначена для инициализации объекта атрибутов условной пере м енной attr значением, действующим по у м олчанию для всех атрибутов, определенных конкретной реализацией.
Если функция pthread_condattr_init () вызывается для уже инициализированного объекта атрибутов attr , то результаты вызова этой функции не определены.
После того как объект атрибутов условной пере м енной уже был использован для инициализации одной или нескольких условных пере м енных, Любая функция, которая оказывает влияние на объект атрибутов (включая деструктор), никак не отразится на ранее инициализированных условных пере м енных.
Этот то м стан д арта IEEE Std 1003.1-2001 требует наличия д вух атрибутов: clock и process-shared.
Дополнительные атрибуты, их значения по умолчанию и имена соответствующих функций доступа, которые считывают и устанавливают эти значения атрибутов, определяются конкретной реализацией.
Возвращаемые значения
При успешно м завершении функции pthread_condattr_destroy() Hpthread_condattr_init() возвращают нулевое значение; в противном случае — код ошибки, обозначающий ее характер.
Ошибки
Функция pthread_condattr_destroy () может завершиться неудачно, если:
[EINVAL] значение, заданное параметром аttr, недействительно.
Функция pthread_condattr_init () завершится неудачно, если:
[ENOMEM] для инициализации объекта атрибутов условной переменной недостаточно существующей памяти. Эти функции не возвращают код ошибки [EINTR].
Примеры
Отсутствуют.
Замечания по использованию