Question

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
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top