Организация параллельных потоков. Часть 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).

Эта директива организует параллельное выполнение разных итераций цикла несколькими потоками.