Редукция в директиве parallel for
Редукция в директиве parallel for
Часто в цикле накапливается значение некоторой переменной, перед циклом эта переменная инициализируется, а на каждой итерации к ней добавляется некоторое значение или умножается на некоторое значение. Эта переменная должна быть объявлена вне цикла, а значит, будет общей. В таком случае возможны ошибки при параллельном выполнении:
var a: integer:=0;
{$omp parallel for}
for var i:integer:=1 to 100 do
a := a+1;
Два потока могут считать старое значение, затем первый поток прибавит единицу и запишет в переменную a, затем второй поток прибавит единицу к старому значению и запишет результат в переменную a. При этом изменения, сделанные первым потоком, будут потеряны. Правильная работа программы возможна при некоторых запусках, но возможны и ошибки.
Опция reduction позволяет обеспечить правильное накопление результата:
{$omp parallel for reduction(действие : список переменных)}
При этом все переменные из списка будут объявлены частными, таким образом, разные потоки будут работать со своими экземплярами переменных. Эти экземпляры будут инициализированы в зависимости от действия, а в конце цикла новое значение переменной будет получено из значения этой переменной до цикла и всех частных копий применением действия из опции.
var a: integer := 1;
{$omp parallel for reduction(+:a)}
for var i: integer:=1 to 2 do
a := a+1;
Здесь начальное значение переменной a – единица, для действия + локальные копии будут инициализированы нулями, будет выполнено две итерации и у каждого потока локальная копия переменной a примет значение 1. После завершения цикла к начальному значению (1) будут прибавлены обе локальные копии, и результирующее значение переменной a будет равно 3, так же как и при последовательном выполнении.
В таблице приведены допустимые операторы редукции и значения, которыми инициализируются локальные копии переменной редукции:
Оператор раздела reduction
Инициализированное значение
+
0
*
1
-
0
and (побитовый)
~0 (каждый бит установлен)
or (побитовый)
0
xor (побитовый)
0
and (логический)
true
or (логический)
false