我试图准确理解为什么在并行区域中发生死锁时,关键构造嵌套在关键构造中。
我咨询了以下资源:作者撰写的this来源:
在OpenMP中,如果在一个关键区域内调用一个函数,就会发生这种情况 包含另一个关键区域。在这种情况下,被叫的关键区域 函数将等待第一个关键区域终止 - 这将永远不会 发生。
好吧,但为什么不呢?此外来自:Hager,Georg和Gerhard Wellein。为科学家和工程师介绍高性能计算。 CRC Press,2010,p。 149:
当线程在关键区域内遇到CRITICAL指令时,它将永远阻塞。
同样的问题,为什么?
最后,Chapman,Barbara,Gabriele Jost和Ruud Van Der Pas。使用OpenMP:可移植共享内存并行编程。卷。 10.麻省理工学院出版社,2008年也提供了一个使用锁的例子,但没有使用关键结构。
根据我目前的理解,嵌套关键区域中出现死锁的方法有两种:
首先开始:
如果两个线程到达嵌套的关键构造(一个关键区域在另一个内部),则线程1进入“外部”关键区域,线程2等待。引用Chapman等人。
当一个线程遇到一个关键构造时,它会一直等到没有其他线程 执行具有相同名称的关键区域。
好吧,到目前为止一切顺利。现在,第一个线程不会进入嵌套的关键区域,因为它是一个同步点,线程在继续之前等待所有其他线程到达。并且由于第二个线程正在等待第一个线程退出“外部”关键区域,因此它们处于死锁状态。
结束先拍摄。
开始第二次拍摄:
两个线程都到达“外部”关键构造。线程1进入“外部”关键构造,线程2等待。现在,线程一进入“内部”关键构造并停止它的隐含障碍,因为它等待第二个线程。另一方面,线程2等待线程1退出到“外部”线程,因此两者都在等待。
结束第二次拍摄。
这是一个产生死锁的小型Fortran代码:
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
所以我的问题是,这两个建议中的一个是正确的,还是有另一种可能性 为什么在这种情况下发生僵局。
答案 0 :(得分:4)
没有隐含的障碍,即没有"同步点,其中线程等待其他线程到达"与CRITICAL结构相关联。相反,在关键构造的开头,线程等待已经在中的任何线程一个同名的关键构造离开构造。
关键构造具有相同的名称不能嵌套,因为当前的OpemMP规则说它们不能(参见OpemMP 4.0第2.16节中的嵌套限制)。这真的是你的问题的答案和讨论的结束 - 如果你违反禁令,那么任何事情都可能发生。
实际上,这种禁止允许实现假设具有相同名称的关键结构不会嵌套。一个常见的实现选择是,遇到关键构造的线程将等待所有线程包括其自身离开构造。如果等待一个线程不能离开。这导致僵局。
可以嵌套具有不同名称的关键构造。如果嵌套不一致,则在这种情况下可能出现死锁。考虑:
!$OMP PARALLEL
!$OMP CRITICAL (A)
!$OMP CRITICAL (B) ! Thread one waiting here.
!...
!$OMP OMP CRITICAL (B)
!$OMP END CRITICAL (A)
!$OMP CRITICAL (B)
!$OMP CRITICAL (A) ! Thread two waiting here.
!...
!$OMP OMP CRITICAL (A)
!$OMP END CRITICAL (B)
!$END PARALLEL
如果出现这种情况,线程将会等待很长时间。