Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
Точно так происходит и в нашем примере с выводом графики на дисплей. Основной поток должен дождаться того момента, когда все рабочие потоки завершат работу, и только затем можно начинать следующую часть программы.
Однако, отметьте для себя одну важную отличительную особенность. С применением функции pthread_join мы ожидаем завершения потоков. Это означает, что на момент ее разблокирования потоков нет больше с нами; они закончили работу и завершились.
В случае с барьером, мы ждем «встречи» определенного числа потоков у барьера. Затем, когда заданное число потоков достигнуто, мы их всех разблокируем (заметьте, что потоки при этом продолжат выполнять свою работу).
Сначала барьер
Эта функция создает объект типа «барьер» по переданному ей адресу (указатель на барьер хранится в параметре barrier) и назначает ему атрибуты, которые определены в attr (мы будем использовать NULL, чтобы установить значения по умолчанию). Число потоков, которые должны вызывать функцию barrier_wait, передается в параметре count.
После того как барьер создан, каждый из потоков должен будет вызвать функцию barrier_wait, чтобы сообщить, что он отработал:
После того как поток вызвал barrier_wait, он будет блокирован до тех пор, пока число потоков, указанное первоначально в параметре count функции barrier_init, не вызовет функцию barrier_wait (они также будут блокированы). После того как нужное число потоков выполнит вызов функции barrier_wait, все эти потоки будут разблокированы «одновременно».
Вот пример:
Основной поток создал объект типа «барьер» и инициализировал его значением счетчика, равным числу потоков (включая себя!), которые должны «встретиться» у барьера, прежде чем он «прорвется». В нашем примере этот индекс был равен 3 — один для потока main, один для потока thread1 и один для потока thread2. Затем, как и прежде, стартуют потоки вычисления графики (в нашем случае это потоки thread1 и thread2). Для примера вместо приведения реальных алгоритмов графических вычислений мы просто временно «усыпили» потоки, указав в них
Как упоминалось ранее, с функцией pthread_join рабочие потоки для синхронизации главного потока с ними должны умереть. В случае же с барьером потоки живут и чувствуют себя вполне хорошо. Фактически, отработав, они просто разблокируются по функции barrier_wait. Тонкость здесь в том, что вы обязаны предусмотреть, что эти потоки должны делать дальше! В нашем примере с графикой мы не дали им никакого задания для них — просто потому что мы так придумали алгоритм. В реальной жизни вы могли бы захотеть, например, продолжить вычисления.