Условная переменная представляет собой семафор, используемый для сигнализации о событии, которое произошло. Сигнала о том, что произошло некоторое событие, может ожидать один или несколько процессов (или потоков) от других процессов или потоков. Следует понимать различие между условными переменными и рассмотренными выше мьютексными семафорами. Назначение мьютексного семафора и блокировок чтения-записи — синхронизировать доступ к данным, в то время как условные переменные обычно используются для синхронизации последовательности операций. По этому поводу в своей книге UNIX Network Programming прекрасно высказался Ричард Стивенс (W. Richard Stevens): « Мьютексы нужно использовать для блокирования, а не для ожидания ».
В листинге 4.6 поток-«потребитель» содержал цикл:
15 while(TextFiles.empty())
16 {}
Поток-«потребитель» выполнял итерации цикла до тех пор, пока в очереди TextFilesбыли элементы. Этот цикл можно заменить условной пере м енной. Поток-«изготовитель» сигналом уведомляет потребителя о том, что в очередь помещены элементы. Поток-«потребитель» может ожидать до тех пор, пока не получит сигнал, а затем перейдет к обработке очереди.
Условная переменная имеет тип pthread_cond_t. Ниже перечислены типы операций, которые может она выполнять:
• инициализация;
• разрушение;
• ожидание;
• ожидание с ограничением по времени;
• адресная сигнализация;
• всеобщая сигнализация;
Операции инициализации и разрушения выполняются условными переменными подобно аналогичным операциям других мьютексов. Функции класса pthread_cond_t,которые реализуют эти операции, перечислены в табл. 5.7.
Ожидание |
int pthread_cond_wait(pthread_cond_t * restrict cond, pthread_mutex_t *restrict mutex); |
int pthread_cond_timedwait( pthread_cond_t * restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); |
Сигнализация |
int pthread_cond_signal(pthread_cond_t*cond); |
int pthread_cond_broadcast( pthread_cond_t *cond); |
Разрушение |
int pthread_cond_destroy(pthread_cond_t*cond); |
Инициализация |
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); |
|
pthread_cond_t cond =PTHREAD_C OND_INITIALIZER; |
Таблица 5.7. Функции класса pthread_cond_t, которые реализуют операции условных переменных
Условные переменные используются совместно с мьютексами. При попытке заблокировать мьютекс поток или процесс будет заблокирован до тех пор, пока мьютекс не освободится. После разблокирования поток или процесс получит мьютекс и продолжит свою работу. При использовании условной переменной ее необходимо связать с мьютексом.
//. . .
pthread_mutex_lock(&Mutex) ;
pthread_cond_wait(&EventMutex, &Mutex);
//. . .
pthread_mutex_unlock(&Mutex) ;
Итак, некоторая задача делает попытку заблокировать мьютекс. Если мьютекс уже заблокирован, то эта задача блокируется. После разблокирования задача освободит мьютекс Mutex и при этом будет ожидать сигнала для условной переменной EventMutex .Если мьютекс не заблокирован, задача будет ожидать сигнала неограниченно долго. При ожидании с ограничением по времени задача будет ожидать сигнала в течение заданного интервала времени. Если это время истечет до получения задачей сигнала, функция возвратит код ошибки. Затем задача вновь затребует мьютекс.
Выполняя адресную сигнализацию, задача уведомляет другой поток или процесс о том, что произошло некоторое событие. Если задача ожидает сигнала для заданной условной переменной, эта задача будет разблокирована и получит мьютекс. Если сразу несколько задач ожидают сигнала для заданной условной переменной, то разблокирована будет только одна из них. Остальные задачи будут ожидать в очереди, и их разблокирование будет происходить в соответствии с используемой стратегией планирования. При выполнении операции всеобщей сигнализации уведомление получат все задачи, ожидающие сигнала для заданной условной переменной. При разблокировании нескольких задач они будут состязаться за право владения мьютексом в соответствии с используемой стратегией планирования. В отличие от операции ожидания, задача, выполняющая операцию сигнализации, не предъявляет прав на владение мьютексом, хотя это и следовало бы сделать.
Условная переменная также имеет атрибутный объект, функции которого перечислены в табл. 5.8.
Таблица 5.8. Функции доступа к атрибутному объекту для условной переменной типа pthread_cond_t
• int pthread_condattr_init( pthread_condattr_t * attr) Инициализирует атрибутный объект условной переменной, заданный параметром attr, значениями, действующими по умолчанию для всех атрибутов, определенных реализацией;
Читать дальше