Я пытаюсь точно понять, почему возникает тупик, когда в параллельной области критическая конструкция вложена в критическую конструкцию.
Я воспользовался следующими ресурсами: этот источник пишет автор:
В OpenMP это может произойти, если внутри критической области вызывается функция, которая содержит другую критическую область. В этом случае критическая область вызываемой функции будет ждать завершения первой критической области - чего никогда не произойдет.
Хорошо, а почему бы и нет? Также от: Hager, Georg и Gerhard Wellein. Введение в высокопроизводительные вычисления для ученых и инженеров. CRC Press, 2010, стр. 149:
Когда поток встречает директиву CRITICAL внутри критической области, он блокируется навсегда.
Тот же вопрос, почему?
Наконец, Чапман, Барбара, Габриэле Йост и Рууд Ван Дер Пас. Использование OpenMP: параллельное программирование переносимой общей памяти. Vol. 10. MIT press, 2008 также приводит пример использования замков, но не с критической конструкцией.
Насколько я понимаю, существует два возможных пути возникновения тупика во вложенной критической области:
Начните с первого дубля:
Если два потока достигают вложенной критической конструкции (одна критическая область внутри другой), первый поток входит во «внешнюю» критическую область, а второй поток ожидает. Цитируя Chapman et al.
Когда поток встречает критическую конструкцию, он ждет, пока ни один другой поток не выполнит критическую область с тем же именем.
Хорошо, пока все хорошо. Теперь первый поток НЕ входит во вложенную критическую область, потому что это точка синхронизации, в которой потоки ожидают прибытия всех остальных потоков, прежде чем продолжить. А поскольку второй поток ожидает выхода первого потока из «внешней» критической области, они находятся в тупике.
Конец первого дубля.
Начните второй дубль:
Оба потока достигают «внешней» критической конструкции. Первый поток входит во «внешнюю» критическую конструкцию, второй поток ожидает. Теперь первый поток ВХОДИТ во «внутреннюю» критическую конструкцию и останавливается на подразумеваемом барьере, потому что он ждет второго потока. Второй поток, с другой стороны, ожидает выхода первого потока во «внешний» поток, поэтому оба ждут вечно.
Конец второго дубля.
Вот небольшой код на Фортране, который вызывает тупик:
1 subroutine foo
2
3 !$OMP PARALLEL
4 !$OMP CRITICAL
5 print*, 'Hallo i am just a single thread and I like it that way'
6 !$OMP END CRITICAL
7 !$OMP END PARALLEL
8
9 end subroutine foo
10
11 program deadlock
12 implicit none
13 integer :: i,sum = 0
14
15 !$OMP PARALLEL
16 !$OMP DO
17 do i = 1, 100
18 !$OMP CRITICAL
19 sum = sum + i
20 call foo()
21 !$OMP END CRITICAL
22 enddo
23 !$OMP END DO
24 !$OMP END PARALLEL
25
26 print*, sum
27 end program deadlock
Итак, мой вопрос: правильно ли одно из двух предложений или есть другая возможность, почему в этой ситуации возникает тупик.