面试题答案
一键面试变量属性设置
sum
变量:由于sum
是全局变量且用于累加计算结果,它需要在线程间共享。所有线程都要对其进行读写操作,以实现最终的累加。local_array
数组:local_array
是局部数组,在每个线程内独立使用,所以应该设置为私有。每个线程有自己独立的副本,互不干扰。
并行化代码示例
program parallel_example
use omp_lib
implicit none
integer :: i, n
real :: sum
real, dimension(100) :: local_array
n = 10000
sum = 0.0
!$omp parallel private(i, local_array) shared(sum, n)
local_array = 0.0
!$omp do
do i = 1, n
local_array(mod(i, 100) + 1) = local_array(mod(i, 100) + 1) + real(i)
end do
!$omp critical
sum = sum + sum(local_array)
!$omp end critical
!$omp end parallel
write(*,*) 'Final sum:', sum
end program parallel_example
竞争条件及避免方法
- 竞争条件:在对
sum
进行累加操作时,如果多个线程同时读写sum
,就会出现竞争条件。例如,线程A读取sum
的值,还未完成更新操作时,线程B也读取了相同的sum
值,这样就会导致更新丢失,最终结果错误。 - 避免方法:使用
critical
指令。在上述代码中,critical
块保证了在任何时刻只有一个线程能够进入该块,对sum
进行更新操作。这样就避免了竞争条件,确保sum
的累加操作正确进行。另外,也可以使用reduction
子句来简化代码并自动处理这种累加的竞争问题,例如:
!$omp parallel private(i, local_array) shared(n) reduction(+:sum)
local_array = 0.0
!$omp do
do i = 1, n
local_array(mod(i, 100) + 1) = local_array(mod(i, 100) + 1) + real(i)
end do
sum = sum + sum(local_array)
!$omp end parallel
reduction(+:sum)
子句自动为每个线程创建sum
的私有副本,在线程结束时将这些私有副本的值累加到全局sum
中,同样避免了竞争条件。