Отметим, что дополнение мьютекса условной переменной делает их комбинацию универсальным базисом, на котором могут быть построены любые сколь угодно сложные в своем поведении объекты синхронизации.
Фактически совместное использование мьютекса и условной переменной создает специфический комбинированный объект синхронизации, который может иметь принципиально более широкое применение, чем отдельно взятый мьютекс. Тем не менее поведение этого объекта синхронизации не столь просто и далеко не очевидно. Рассмотрим его более подробно.
На рис. 4.1 приведена блок-схема операций, выполняемых потоком при использовании мьютекса и условной переменной для синхронизации. Линиями отделены операции, выполняющиеся «внутри» функций, указанных справа. Обратите внимание, что наиболее сложная логика соответствует вызову функции ожидания на условной переменной.
Рис. 4.1
. Схема действий потока при выполнении синхронизации с применением пары мьютекс-условная переменная (обратите внимание, что операции при участии мьютекса (1, 2, 3) выполняются дважды.)Проблема в первую очередь заключается в том, что внутри критической секции, отмеченной вызовами функций pthread_mutex_lock()
pthread_mutex_unlock(), не может находиться более одного потока в единый момент времени. Следовательно, даже если поток, блокированный на условной переменной, и получит pthread_cond_signal() или pthread_cond_broadcast(), он не сможет немедленно продолжить свое выполнение, если внутри критической секции уже находится другой поток. В этом случае разблокированный (на условной переменной) поток изменяет свой статус с «блокированного на условной переменной» (в котором он находился до этого) на статус «блокированного на мьютексе» и пребывает в нем до тех пор, пока текущий владелец не освободит мьютекс.Все функции операций над условной переменной и ее атрибутами реализованы в заголовочном файле
Операции над условной переменной
Параметры условной переменной
int pthread_condattr_init(pthread_condattr_t* attr);
Функция инициализирует структуру атрибутов условной переменной, на которую указывает параметр attr
pthread_condattr_t определена в файле и является производной от типа syncattr_t, описанного в разделе «Параметры мьютекса». При инициализации атрибуты устанавливаются в значения по умолчанию.Возвращаемые значения:
EOK
ENOMEM
attr.Для условной переменной возможна модификация значительно меньшего числа параметров, чем для мьютекса. Следующие функции описывают доступ к этим параметрам.
int pthread_condattr_setpshared(
pthread_condattr_t* attr, int pshared);
int pthread_condattr_getpshared(
const pthread_condattr_t* attr, int* pshared);
Функции устанавливают/считывают, возможен ли доступ к условной переменной из потоков, порожденных в других процессах. Параметр pshared
• PTHREAD_PROCESS_SHARED
• PTHREAD_PROCESS_PRIVATE
PTHREAD_PROCESS_PRIVATE, результат будет не определен.Возвращаемые значения:
EOK
EINVAL
attr, или новое значение, на которое ссылается pshared, не определены.int pthread_condattr_setclock(
pthread_condattr_t* attr, clockid_t id);
int pthread_condattr_getclock(
const pthread_condattr_t* attr, clockid_t* id);
Функции устанавливают/считывают, каким способом (т.e. на основании какого счетчика) вычисляется значение тайм-аута при вызовах pthread_cond_timedwait()
REALTIME_CLOCK в качестве параметра id; это же значение является значением по умолчанию.Возвращаемые значения:
EOK
EINVAL
attr.