errExitEN(s, "pthread_mutex_unlock");
}
Код, показанный выше, работает, но при этом тратит впустую процессорное время, поскольку главный поток постоянно проверяет состояние переменной avail, используя цикл. Эту проблему можно устранить с помощью
Условные переменные всегда используются в сочетании с мьютексами. Мьютекс обеспечивает взаимоисключающий доступ к разделяемому ресурсу, тогда как условная переменная сигнализирует об изменении его состояния (это
30.2.1. Статически выделяемые условные переменные
По аналогии с мьютексами, уловные переменные могут выделяться статически и динамически. Здесь будут рассмотрены статически выделяемые переменные, а динамические мы рассмотрим в подразделе 30.2.5.
Условная переменная имеет тип pthread_cond_t. Как и в случае с мьютексом, перед использованием ее следует инициализировать. В случае со статически выделяемыми условными переменными это делается путем присваивания им значения PTHREAD_COND_INITIALIZER, как показано в следующем примере:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Согласно стандарту SUSv3 применение операций, которые будут описаны в оставшейся части этого раздела, к копии условной переменной приводит к неопределенным результатам. Эти операции всегда должны выполняться с оригиналом условной переменной, инициализированным статически, с помощью значения PTHREAD_COND_INITIALIZER, или динамически, путем вызова pthread_cond_init() (описанного в подразделе 30.2.5).
30.2.2. Оповещение и ожидание условных переменных
Основными операциями с условными переменными являются
Оповещения передаются с помощью аргумента cond в функциях pthread_cond_signal() и pthread_cond_broadcast(). Функция pthread_cond_wait() блокирует поток, пока условная переменная cond не просигнализирует об изменении.
#include
int pthread_cond_signal(pthread_cond_t *
int pthread_cond_broadcast(pthread_cond_t *
int pthread_cond_wait(pthread_cond_t *
Все возвращают 0 при успешном завершении или положительное число, если произошла ошибка
Разница между функциями pthread_cond_signal() и pthread_cond_broadcast() заключается в том, что происходит, когда в вызове pthread_cond_wait() заблокировано несколько потоков. pthread_cond_signal() просто гарантирует, что по меньшей мере один поток возобновит свою работу; pthread_cond_broadcast() разблокирует все потоки сразу.
Использование pthread_cond_broadcast() всегда приводит к корректному результату (поскольку все потоки должны уметь справляться с лишними и ложными возобновлениями работы). Функция pthread_cond_signal() может оказаться более эффективной, но ее следует применять только в том случае, если на изменение состояния разделяемого ресурса должен реагировать только один поток, неважно, какой именно. Этот сценарий обычно относится к случаям, когда все ожидающие потоки спроектированы для выполнения одной и той же задачи. Исходя из этого, функция pthread_cond_signal() может демонстрировать более высокую производительность по сравнению с pthread_cond_broadcast(), поскольку позволяет избежать следующих ситуаций.
1. Все ожидающие потоки возобновили работу.
2. Один из потоков первым получает процессорное время. Он проверяет состояние разделяемой переменной (под защитой соответствующего мьютекса) и видит, что ему необходимо выполнить некие действия. Поток выполняет все, что от него требуется, изменяет состояние разделяемой переменной, чтобы уведомить о завершении работы, и открывает соответствующий мьютекс.
3. Оставшиеся потоки по очереди закрывают мьютекс и проверяют состояние разделяемой переменной. Однако из-за изменений, внесенных первым потоком, им больше нечего делать, поэтому они открывают мьютекс и возвращаются к состоянию ожидания (то есть снова вызывают pthread_cond_wait()).
В отличие от pthread_cond_signal(), функция pthread_cond_broadcast() рассчитана в том числе и на потоки, которые выполняют разные задачи (в этом случае они, скорее всего, имеют разные предикаты, связанные с условной переменной).