Редукция в директиве parallel for

We use cookies. Read the Privacy and Cookie Policy

Редукция в директиве 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