PascalABC.NET

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