Организация параллельных потоков. Часть 2 | страница 12
Соответственно, максимальный номер потока равен числу потоков минус один.
Названия этих двух функций очень похожи, здесь просто другой порядок слов.
Судите сами:
num_threads / thread_num.
Придётся немного освежить английский. Здесь действует так называемое «правило ряда» (цепочка определений). Если идут несколько существительных подряд, то главное слово будет в конце.
Вторая трудность с пониманием названий — слово NUMBER. Оно может означать «количество» или «порядковый номер». Это одно и то же слово, но два разных значения. И переводятся разные значения разными словами. Вообще-то у этого слова ещё штук двадцать других значений, но дальше углубляться мы уже не будем.
Составим программу и посмотрим, как работают эти две функции (рис. 4.3).
Для организации вывода в виде таблицы используем символ табуляции:
\t.
Табуляция смещает начало вывода на 8 позиций.
Таким образом, первое число выводится начиная с 1-й позиции, второе число — с 9-й и т. д.
Табуляция нам ещё пригодится для анализа эффективности и точности.
Рис. 4.3. Номер потока и количество потоков
Запускаем программу и видим сообщения в произвольном порядке (рис. 4.4). Кто первый успел — тот и напечатал. Если запускать программу несколько раз, получим разные результаты.
Рис. 4.4. Список номеров потоков
Задание. Составьте программу (рис. 4.3). Запустите программу несколько раз и обратите внимание на порядок вывода номеров потоков.
4.2. Параллельный цикл
В этом разделе мы организуем параллельное исполнение цикла FOR и исследуем поведение программы. Результаты могут оказаться не совсем очевидными. Это особенности параллельного программирования. Вот с этими особенностями нам и предстоит познакомиться.
4.2.1. Ситуация гонки
При выполнении параллельной программы может возникать так называемая «ситуация гонки». Это соревнование параллельных потоков за доступ к данным. Английское название:
Data Race.
Мы её уже рассматривали в предыдущей работе. Параллельные потоки обращаются к общей переменной и «затирают» чужие результаты, записывая свои. В результате появляется ошибка в расчётах. Причём ошибка будет случайной, непредсказуемой, и при каждом запуске ошибка будет разной.
Начнём с решения задачи распараллеливания цикла «в лоб».
Рассмотрим программу вычисления суммы большого количества единиц в цикле (рис. 4.5).
Перед оператором цикла вставляем следующую строчку:
#pragma omp parallel for (строка 6).
Эта директива организует параллельное выполнение разных итераций цикла несколькими потоками.