103 lines
3.3 KiB
HTML
103 lines
3.3 KiB
HTML
<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>
|
||
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: integer:=1 <b>to</b> 2 <b>do</b><br>
|
||
a := a+1;</code></p>
|
||
</blockquote>
|
||
<p>Здесь начальное значение переменной a – единица, для действия + локальные
|
||
копии будут инициализированы нулями, будет выполнено две итерации и у каждого
|
||
потока локальная копия переменной a примет значение 1. После завершения цикла к
|
||
начальному значению (1) будут прибавлены обе локальные копии, и результирующее
|
||
значение переменной a будет равно 3, так же как и при последовательном
|
||
выполнении. </p>
|
||
<p>В таблице приведены допустимые операторы редукции и значения, которыми
|
||
инициализируются локальные копии переменной редукции:</p>
|
||
<p> </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> |