|
|||
Семинар 14. Тема семинара. Технология OpenМР: операция редукции. Пример 1.Стр 1 из 2Следующая ⇒ Семинар 14 Тема семинара Технология OpenМР: операция редукции
Как мы уже знаем, директива синхронизации critical обеспечивают корректную работу с общими переменными в случае, если требуется, чтобы каждая нить выполнила какую-либо операцию надо общими данными. Другой вариант организации корректной работы с общими данными – операции редукции. Опция reduction прагмы parallel задаёт операцию редукции (сложение, умножение, и т.п.) и список переменных редукции, над которыми указанная операция производится. Операция редукции осуществляется при закрытии параллельной секции, над теми значениями переменных редукции, которые они имеют к моменту закрытия параллельной области в каждой нити. Рассмотрим, как работает редукция в OpenMP, на конкретном примере.
Пример 1. ... int nCount=10; #pragma omp parallel reduction (+ : nCount) { ... nCount+=1; ... } ...
В данном фрагменте целочисленная переменная nCount объявлена переменной редукции, а операцией редукции является сложение. Если переменная объявлена переменной редукции – ее нельзя объявлять локальной или общей, это будет ошибкой. Логика работы с этой переменной следующая. При входе в параллельную область для каждой переменной редукции создаются локальные копии с тем же именем в каждой нити. Начальные значения этих локальных переменных в каждой нити определяются типом операции редукции и никак не связаны со значением переменной с этим именем до начала параллельной области. Так, для операции сложения начальное значение переменной редукции 0, для умножения – 1, см. таблицу в Приложении 4 Учебного пособия по OpenMP. В нашем примере, поскольку операцией редукции является сложение, начальные значения локальных переменных nCount в каждой нити параллельной области равны 0, несмотря на то, что перед началом параллельной области мы имели nCount=10. Итак, при входе в параллельную область каждая нить имеет начальное значение переменной редукции nCount=0. Далее, Каждая нить увеличивает свою переменную nCount на единицу, т.е. при закрытии параллельной области каждая нить имеет nCount=1. При закрытии параллельной области над всеми переменным nCount из каждой нити осуществляется операция редукции (в нашем случае – сложение). Все переменные nCount=1 из всех нитей складываются между собой, и эта сумма прибавляется к тому значению nCount, которое эта переменная имела до объявления параллельной области, т.е. nCount=10. Таким образом, после закрытия параллельной области будем иметь значение переменной nCount, равное 10+количество нитей, что мы и видим при запуске нижеследующего кода с количеством нитей, равным по умолчанию 6.
В необходимости использования опции редукции для корректной работы с общими переменными можно убедиться, если убрать эту опцию и задать достаточно большое количество нитей. В этой ситуации есть вероятность, что одна или более нитей обратится к общему для всех адресу nCount в момент, когда это значение еще не обновлено по результатам работы других нитей, так что результат окажется меньше, чем 10+количество нитей и может меняться от запуска к запуску. Это хорошо видно на скриншоте: при количестве нитей 40 при многократных запусках время от времени получаем nCount =49, nCount =47 и даже nCount =45 вместо nCount =50.
|
|||
|