pascalabcnet/PABCNetHelp/LangGuide/OpenMP/reduction.html

103 lines
4.7 KiB
HTML
Raw Permalink Normal View History

<html>
<head>
<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
<param name="Keyword" value="parallel">
</object>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title></title>
<link rel="StyleSheet" href="../../default.css">
<style>
<!--
table.MsoNormalTable
{mso-style-parent:"";
font-size:10.0pt;
font-family:"Times New Roman";
}
-->
</style>
</head>
<body>
<H1>Редукция в директиве parallel for </H1>
<p>Часто в цикле накапливается значение некоторой переменной, перед циклом эта
переменная инициализируется, а на каждой итерации к ней добавляется некоторое
значение или умножается на некоторое значение. Эта переменная должна быть
объявлена вне цикла, а значит, будет общей. В таком случае возможны ошибки при
параллельном выполнении:</p>
<blockquote>
<p><code><b>var</b> a: integer:=0;<br>
<font color="#666666">{$omp parallel for}<br>
</font><b>for</b> <b>var</b> i:integer:=1 <b>to</b> 100 <b>do</b><br>
&nbsp; a := a+1;</code></p>
</blockquote>
<p>Два потока могут считать старое значение, затем первый поток прибавит единицу
и запишет в переменную a, затем второй поток прибавит единицу к старому значению
и запишет результат в переменную a. При этом изменения, сделанные первым
потоком, будут потеряны. Правильная работа программы возможна при некоторых
запусках, но возможны и ошибки.</p>
<p>Опция <code>reduction</code> позволяет обеспечить правильное накопление результата:</p>
<blockquote>
<p><code><font color="#666666">{$omp parallel for reduction(действие : список переменных)}</font></code></p>
</blockquote>
<p>При этом все переменные из списка будут объявлены частными, таким образом,
разные потоки будут работать со своими экземплярами переменных. Эти экземпляры
будут инициализированы в зависимости от действия, а в конце цикла новое значение
переменной будет получено из значения этой переменной до цикла и всех частных
копий применением действия из опции.</p>
<blockquote>
<p><code><b>var</b> a: integer := 1;<br>
<font color="#666666">{$omp parallel for reduction(+:a)}<br>
</font><b>for</b> <b>var</b> i:=1 <b>to</b> 2 <b>do</b><br>
&nbsp; a := a+1;</code></p>
</blockquote>
<p>Здесь начальное значение переменной a единица, для действия + локальные
копии будут инициализированы нулями, будет выполнено две итерации и у каждого
потока локальная копия переменной a примет значение 1. После завершения цикла к
начальному значению (1) будут прибавлены обе локальные копии, и результирующее
значение переменной a будет равно 3, так же как и при последовательном
выполнении. </p>
<p>В таблице приведены допустимые операторы редукции и значения, которыми
инициализируются локальные копии переменной редукции:</p>
<p>&nbsp;</p>
<table border="1" width="100%" id="table2">
<tr>
<td>Оператор раздела reduction</td>
<td>Инициализированное значение</td>
</tr>
<tr>
<td>+</td>
<td>0</td>
</tr>
<tr>
<td>*</td>
<td>1</td>
</tr>
<tr>
<td>-</td>
<td>0</td>
</tr>
<tr>
<td>and (побитовый)</td>
<td>~0 (каждый бит установлен)</td>
</tr>
<tr>
<td>or (побитовый)</td>
<td>0</td>
</tr>
<tr>
<td>xor (побитовый)</td>
<td>0</td>
</tr>
<tr>
<td>and (логический)</td>
<td>true</td>
</tr>
<tr>
<td>or (логический)</td>
<td>false</td>
</tr>
</table>
</body>
</html>