You can use the THREADLOCAL directive to declare thread-specific common data. It is a possible method of ensuring that access to data that is contained within COMMON blocks is serialized.
In order to make use of this directive it is not necessary to specify the -qsmp compiler option, but the invocation command must be xlf_r, xlf_r7, xlf90_r, xlf90_r7, xlf95_r, or xlf95_r7 to link the necessary libraries.
.-,-----------------------. V | >>-THREADLOCAL--+----+----/--common_block_name--/-+------------>< '-::-'
You can only declare named blocks as THREADLOCAL. All rules and constraints that normally apply to named common blocks apply to common blocks that are declared as THREADLOCAL. See COMMON for more information on the rules and constraints that apply to named common blocks.
The THREADLOCAL directive must appear in the specification_part of the scoping unit. If a common block appears in a THREADLOCAL directive, it must also be declared within a COMMON statement in the same scoping unit. The THREADLOCAL directive may occur before or after the COMMON statement. See Main Program for more information on the specification_part of the scoping unit.
A common block cannot be given the THREADLOCAL attribute if it is declared within a PURE subprogram.
Members of a THREADLOCAL common block must not appear in NAMELIST statements.
A common block that is use-associated must not be declared as THREADLOCAL in the scoping unit that contains the USE statement.
Any pointers declared in a THREADLOCAL common block are not affected by the -qinit=f90ptr compiler option.
Objects within THREADLOCAL common blocks may be used in parallel loops and parallel sections. However, these objects are implicitly shared across the iterations of the loop, and across code blocks within parallel sections. In other words, within a scoping unit, all accessible common blocks, whether declared as THREADLOCAL or not, have the SHARED attribute within parallel loops and sections in that scoping unit.
If a common block is declared as THREADLOCAL within a scoping unit, any subprogram that declares or references the common block, and that is directly or indirectly referenced by the scoping unit, must be executed by the same thread executing the scoping unit. If two procedures that declare common blocks are executed by different threads, then they would obtain different copies of the common block, provided that the common block had been declared THREADLOCAL. Threads can be created in one of the following ways:
If a common block is declared to be THREADLOCAL in one scoping unit, it must be declared to be THREADLOCAL in every scoping unit that declares the common block.
If a THREADLOCAL common block that does not have the SAVE attribute is declared within a subprogram, the members of the block become undefined at subprogram RETURN or END, unless there is at least one other scoping unit in which the common block is accessible that is making a direct or indirect reference to the subprogram.
You cannot specify the same common_block_name for both a THREADLOCAL directive and a THREADPRIVATE directive.
Example 1: The following procedure "FORT_SUB" is invoked by two threads:
SUBROUTINE FORT_SUB(IARG) INTEGER IARG CALL LIBRARY_ROUTINE1() CALL LIBRARY_ROUTINE2() ... END SUBROUTINE FORT_SUB
SUBROUTINE LIBRARY_ROUTINE1() COMMON /BLOCK/ R ! The SAVE attribute is required for the common SAVE /BLOCK/ ! block because the program requires that the block !IBM* THREADLOCAL /BLOCK/ ! remain defined after library_routine1 is invoked. R = 1.0 ... END SUBROUTINE LIBRARY_ROUTINE1
SUBROUTINE LIBRARY_ROUTINE2() COMMON /BLOCK/ R SAVE /BLOCK/ !IBM* THREADLOCAL /BLOCK/ ... = R ... END SUBROUTINE LIBRARY_ROUTINE2
Example 2: "FORT_SUB" is invoked by multiple threads. This is an invalid example because "FORT_SUB" and "ANOTHER_SUB" both declare /BLOCK/ to be THREADLOCAL. They intend to share the common block, but they are executed by different threads.
SUBROUTINE FORT_SUB() COMMON /BLOCK/ J INTEGER :: J !IBM* THREADLOCAL /BLOCK/ ! Each thread executing FORT_SUB ! obtains its own copy of /BLOCK/ INTEGER A(10) ... !IBM* INDEPENDENT DO INDEX = 1,10 CALL ANOTHER_SUB(A(I)) END DO ... END SUBROUTINE FORT_SUB
SUBROUTINE ANOTHER_SUB(AA) ! Multiple threads are used to execute ANOTHER_SUB INTEGER AA COMMON /BLOCK/ J ! Each thread obtains a new copy of the INTEGER :: J ! common block /BLOCK/ !IBM* THREADLOCAL /BLOCK/ ... AA = J ! The value of 'J' is undefined. END SUBROUTINE ANOTHER_SUB