
Координация и синхронизация работы потоков
В системе Linux предусмотрено три механизма синхронизации: мьютексы, семафоры и условные переменные.
1) В потоках мьютексы используются для обеспечения взаимно исключающего доступа к разделяемому элементу данных. Мьютекс инициализируется динамически путем вызова функции pthread_mutex_init. Следует предусматривать применение отдельного мьютекса для каждого элемента данных, который должен быть защищен. Перед использованием элемента данных поток вызывает функцию pthread_mutex_lock и функцию pthread_mutex_unlock по окончании его использования. Эти два вызова позволяют одновременно обращаться к элементу данных только одному потоку. Первый поток, вызвавший функцию pthread_mutex_lock с конкретным мьютексом, продолжает свою работу без задержки. Однако система блокирует каждый следующий поток, вызывающий функцию pthread_mutex_lock с тем же мьютексом. Когда вызывается функция pthread_mutex_unlock операционная система разблокирует один из ожидающих освобождения этого мьютекса потоков.
2) Семафор представляет собой механизм синхронизации, обобщающий мьютекс и применяемый в том случае, если доступно N копий ресурса. Семафор инициализируется динамически. Для инициализации семафора применяется функция sem_init; в одном из ее параметров должен быть указан начальный счетчик N. Сразу после инициализации семафора поток вызывает функцию sem_wait до начала использования одной копии ресурса, а возвращая копию для использования другими потоками, вызывает функцию sem_post. Функция sem_wait может быть беспрепятственно вызвана потоками, число которых составляет N; после ее вызова каждый из них продолжает свое выполнение. Однако если к семафору попытаются обратиться дополнительные потоки, они будут заблокированы и будут заблокированными до тех пор, пока один из выполняющихся потоков не вызовет функцию sem_post.
3) Условные переменные требуются только в ситуации, при которой одновременно выполняются следующие два условия: ряд потоков использует мьютекс для получения взаимно исключающего доступа к некоторому ресурсу и сразу после приобретения ресурса поток должен перейти к ожиданию возникновения определенного события.
Без применения условных переменных в программах, которые сталкиваются описанной выше ситуацией, приходится использовать своего рода активное задание, в котором поток повторно приобретает мьютекс, проверяет условие, а затем освобождает мьютекс. Перед блокировкой на условной временной поток приобретает мьютекс. При вызове потоком функции pthread_cond_wait для перехода в состояние ожидания изменения условной переменной в потоке должна быть указана и условная переменная, изменения которой он ожидает, и захваченный им мьютекс. Операционная система освобождает мьютекс, захваченный потоком, и одновременно с этим блокирует поток в ожидании изменения условной переменной.
После выполнения функции pthread_cond_wait поток блокируется на указаной условной переменной до тех пор, пока какой-то другой поток не передаст сигнал об изменении этой переменной. Для передачи сигнала об изменении условной переменной могут применяться два способа; различие между ними определяется тем, что многочисленные ожидающие потоки могут обрабатываться по разному. Функция pthread_cond_signal позволяет продолжить работу только одному потоку, даже если сигнала об изменении состояния переменной ожидают несколько потоков, а функция pthread_cond_broadcast позволяет продолжить работу всем потокам, заблокированным на этой переменной. Разрешая одному потоку продолжить работу, операционная система одновременно разблокирует этот поток и позволяет ему снова приобрести мьютекс, которым он обладал, прежде чем заблокироваться на условной переменной, об изменении состояния которой получен сигнал. Ожидание изменения условной переменной равносильно отказу на время от мьютекса, а затем автоматическому повторному приобретению этого мьютекса после поступления сигнала об изменении условной переменной. В результате блокировка потока на условной переменной не исключает для других потоков возможности пройти через критический участок, поскольку мьютекс могут приобрести и другие потоки.