I have a textbook example that demonstrates fixing data scoping through parameters. I am wondering why in the code snippet below the author uses a COMMON block to define two variables, istart and iend, ** that are supposed to be private for each thread? Does not the "shared" property of variables with the COMMON attribute conflict with the author's intention to specify **istart and iend as private? Or should we simply remove the common block?
The author says, "We use a common block named bounds containing istart and iend, essentially containing the values used in both the main program and the subroutine." I am wondering if the common attribute will be inherited by the calling subroutine of each thread and interfere the "private" property which istart and iend are supposed to bear.
Lee
program main
...
common /bounds/ istart,iend
integer :: iarray(10000),N
N=10000
...
!$omp parallel private(iam,nthreads,chunk), &
!$omp& private(istart,iend)
nthreads=omp_get_num_threads()
iam = omp_getthread_num()
chunk=(N+nthreads-1)/nthreads
istart=iam*chunk+1
iend=min((iam+1)*chunk,N)
call work(iarray,istart,iend)
!$omp end parallel
end program main
subroutine work(iarray,istart,iend)
...
integer :: iarray(10000)
do i=istart,iend
iarray(i)=i*i
endddo
end subroutine work
In the other example, the author writes the following code snippet for the same purpose. In this case, I should keep the common block in both the main and subroutine procedures, right?
program main
...
common /bounds/ istart, iend
!$omp threadprivate(/bounds/)
integer iarray(10000)
N = 10000
!$omp parallel private(iam, nthreads, chunk)
nthreads = omp_get_num_threads()
iam = omp_get_thread_num()
chunk = (N + nthreads – 1)/nthreads
istart = iam * chunk + 1
iend = min((iam + 1) * chunk, N)
call work(iarray)
!$omp end parallel
end program main
subroutine work(iarray)
...
common /bounds/ istart, iend
!$omp threadprivate(/bounds/)
integer iarray(10000)
do i = istart, iend
iarray(i) = i * i
enddo
end subroutine work
If I like to pass the variables istart and iend in a modern manner, am I correct at making the following revision (which looks a little weird to me because the argument of the threadprivate clause is not the names of common blocks):
program main
use model
...
!$omp threadprivate(istart,iend)
integer iarray(10000)
N = 10000
!$omp parallel private(iam, nthreads, chunk)
nthreads = omp_get_num_threads()
iam = omp_get_thread_num()
chunk = (N + nthreads – 1)/nthreads
istart = iam * chunk + 1
iend = min((iam + 1) * chunk, N)
call work(iarray)
!$omp end parallel
end program main
module model
integer :: istart,iend
contains
subroutine work(iarray)
...
!$omp threadprivate(istart,iend)
integer iarray(10000)
do i = istart, iend
iarray(i) = i * i
enddo
end subroutine work
end module model
If this more or less the complete example I don't see any place for the common block. No actual sharing happens here, because the values are private to each thread in the parallel
block and they are passed as dummy arguments.
I would really remove it.
The other case is different. Here the variables are shared using the common block and privatized using threadprivate
. This is a correct usage, although more modern style is to use module variables the same way.
With modules I would do:
module parameters
integer :: istart,iend
!$omp threadprivate(istart,iend)
end module
module model
use parameters
implicit none
contains
subroutine work(iarray)
...
integer iarray(10000)
do i = istart, iend
iarray(i) = i * i
enddo
end subroutine work
end module model
program main
use parameters !not completely necessary here
use model
implicit none
...
integer iarray(10000)
N = 10000
!$omp parallel private(iam, nthreads, chunk)
nthreads = omp_get_num_threads()
iam = omp_get_thread_num()
chunk = (N + nthreads – 1)/nthreads
istart = iam * chunk + 1
iend = min((iam + 1) * chunk, N)
call work(iarray)
!$omp end parallel
end program main
Notice the threadprivate
directive is used only at the declaration of the variables used in it.
Remark, common
is not an attribute of a variable, it is a separate entity containing the variables. Therefore there is no way the dummy arguments could inherit common
.