THREADPRIVATE

用途

THREADPRIVATE 指引可讓您將具名共用區塊及具名變數指定為執行緒專用,但在該執行緒內是廣域的。 一旦您宣告共同區塊或變數 THREADPRIVATE,團隊中的每一個執行緒都會維護該共同區塊或變數的個別副本。 寫入 THREADPRIVATE 共用區塊或變數的資料會保持該執行緒的專用狀態,且不會對團隊中的其他執行緒顯示。

在程式的序列及 MASTER 區段中,只能存取 主要 執行緒的具名共用區塊及變數副本。

PARALLELPARALLEL DOPARALLEL SECTIONSPARALLEL WORKSHARE 指引上使用 COPYIN 子句,指定在進入平行區域時, 主要 執行緒的具名共用區塊或具名變數副本中的資料會複製到每個執行緒的該共用區塊或變數專用副本。

必要選項

-qsmp

語法

讀取語法圖跳過視覺化語法圖THREADPRIVATE( threadprivate_entity_list )

其中 threadprivate_entity_list 是:

讀取語法圖跳過視覺化語法圖,variable_name/common_block_name/
common_block_name
是要成為執行緒專用的共用區塊名稱。
變數名稱
是要成為執行緒專用的變數名稱。

規則

您無法在 PRIVATEFIRSTPRIVATELASTPRIVATESHAREDREDUCTION 子句中指定 THREADPRIVATE 變數、共用區塊或組成該共用區塊的變數。

THREADPRIVATE 變數必須具有 SAVE 屬性。 對於模組範圍中宣告的變數或一般區塊,隱含有 SAVE 屬性。 如果您在模組範圍之外宣告變數,則必須指定 SAVE 屬性。

THREADPRIVATE 指引中,您只能指定具名變數及具名共用區塊。

變數只能出現在其宣告範圍內的 THREADPRIVATE 指引中,而 THREADPRIVATE 變數或共同區塊在給定範圍內只能出現一次。 變數不能是共同區塊的元素,也不能在 EQUIVALENCE 陳述式中宣告。

您不能同時對 THREADPRIVATE 指引和 THREADLOCAL 指引指定相同的 common_block_name

適用於具名共用區塊的所有規則及限制也適用於宣告為 THREADPRIVATE的共用區塊。 請參閱 COMMON 陳述式

如果您在一個範圍設定單元中將共用區塊宣告為 THREADPRIVATE ,則必須在宣告它的所有其他範圍設定單元中將它宣告為 THREADPRIVATE

如果您使用 BIND 屬性來宣告 THREADPRIVATE 變數或 THREADPRIVATE 共用區塊,則必須在 C 程式的 THREADPRIVATE 指引中指定對應的 C 實體。 如需詳細用法資訊,請參閱 範例 4

進入任何平行區域時,在 COPYIN 子句中指定的 THREADPRIVATE 共同區塊中的 THREADPRIVATE 變數或變數會受到 COPYIN 子句的 Rules 區段中所述的準則所規範。

進入程式的第一個平行區域時, THREADPRIVATE 共同區塊內未在 COPYIN 子句中指定的 THREADPRIVATE 變數或變數會遵循下列準則:
  • 如果變數具有 ALLOCATABLE 屬性,則目前不會配置該變數每一個副本的起始配置狀態。
  • 如果變數具有 POINTER 屬性,且該指標透過明確或預設起始設定取消關聯,則該變數的每一個副本的關聯狀態會取消關聯。 否則,指標的關聯狀態未定義。
  • 如果變數既沒有 ALLOCATABLE 也沒有 POINTER 屬性,而且是透過明確或預設起始設定來定義,則會定義該變數的每一個副本。 如果變數未定義,則該變數的每一個副本都未定義。
進入程式的後續平行區域時, THREADPRIVATE 變數或 THREADPRIVATE 共用區塊內未在 COPYIN 子句中指定的變數會遵循下列準則:
  • 如果您使用 OMP_DYNAMIC 環境變數或 omp_set_dynamic 子常式來啟用動態執行緒及:
    • 如果執行緒數目小於前一個區域中的執行緒數目,且在兩個區域中都參照 THREADPRIVATE 物件,則在其各自區域中具有相同執行緒數目的執行緒會參照該變數的相同副本。
    • 如果執行緒數目大於前一個區域中的執行緒數目,則未定義 THREADPRIVATE 物件的定義及關聯狀態,且未定義配置狀態。
  • 如果停用動態執行緒,則會保留定義、關聯或配置狀態及定義 (如果已定義執行緒的變數副本)。

您無法透過使用關聯或主機關聯來存取共用區塊的名稱。 因此,如果共用區塊在包含 THREADPRIVATE 指引的範圍設定單元中宣告,則具名共用區塊只能出現在 THREADPRIVATE 指引上。 不過,您可以使用關聯或主機關聯來存取共用區塊中的變數。 如需相關資訊,請參閱 主機使用關聯

-qinit=f90ptr 編譯器選項不會影響您在 THREADPRIVATE 共用區塊中宣告的指標。

DEFAULT 子句不會影響 THREADPRIVATE 共同區塊中的變數。

範例

Example 1: 在此範例中, PARALLEL DO 指引會呼叫多個呼叫 SUB1的執行緒。 SUB1 中的共用區塊 BLK 與子常式 SUB2(由 SUB1呼叫) 共用執行緒特定的資料。

      PROGRAM TT
        INTEGER :: I, B(50)

!$OMP   PARALLEL DO SCHEDULE(STATIC, 10)
        DO I=1, 50
          CALL SUB1(I, B(I))       ! Multiple threads call SUB1.
        ENDDO
      END PROGRAM TT

      SUBROUTINE SUB1(J, X)
        INTEGER :: J, X, A(100)
        COMMON /BLK/ A
!$OMP   THREADPRIVATE(/BLK/)   ! Array a is private to each thread.
!  ...
        CALL SUB2(J)
        X = A(J) + A(J + 50)
!  ...
      END SUBROUTINE SUB1

      SUBROUTINE SUB2(K)
        INTEGER :: C(100)
        COMMON /BLK/ C
!$OMP   THREADPRIVATE(/BLK/)
!  ...
        C = K
!  ...                       ! Since each thread has its own copy of
                             ! common block BLK, the assignment of
                             ! array C has no effect on the copies of
                             ! that block owned by other threads.
END SUBROUTINE SUB2

Example 2: 在此範例中,每一個執行緒在平行區段中都有自己的共同區塊副本 ARR 。 如果一個執行緒起始設定一般區塊變數 TEMP,則其他執行緒無法看到起始值。

      PROGRAM ABC
        INTEGER :: I, TEMP(100), ARR1(50), ARR2(50)
        COMMON /ARR/ TEMP
!$OMP   THREADPRIVATE(/ARR/)
        INTERFACE
          SUBROUTINE SUBS(X)
            INTEGER :: X(:)
          END SUBROUTINE
        END INTERFACE
! ...
!$OMP   PARALLEL SECTIONS
!$OMP   SECTION                   ! The thread has its own copy of the
! ...                             ! common block ARR.
          TEMP(1:100:2) = -1
          TEMP(2:100:2) = 2
          CALL SUBS(ARR1)
! ...
!$OMP   SECTION                   ! The thread has its own copy of the
! ...                             ! common block ARR.
          TEMP(1:100:2) = 1
          TEMP(2:100:2) = -2
          CALL SUBS(ARR2)
! ...
!$OMP    END PARALLEL SECTIONS
! ...
        PRINT *, SUM(ARR1), SUM(ARR2)
      END PROGRAM ABC

      SUBROUTINE SUBS(X)
        INTEGER :: K, X(:), TEMP(100)
        COMMON /ARR/ TEMP
!$OMP   THREADPRIVATE(/ARR/)
!  ...
        DO K = 1, UBOUND(X, 1)
          X(K) = TEMP(K) + TEMP(K + 1)    ! The thread is accessing its
                                          ! own copy of
                                          ! the common block.
        ENDDO
! ...
      END SUBROUTINE SUBS

此程式的預期輸出為:

50 -50

Example 3: 在下列範例中,共同區塊外部的區域變數宣告為 THREADPRIVATE

      MODULE MDL
        INTEGER          :: A(2)
        INTEGER, POINTER :: P
        INTEGER, TARGET  :: T
!$OMP THREADPRIVATE(A, P)
      END MODULE MDL


      PROGRAM MVAR
      USE OMP_LIB
      USE MDL

      INTEGER :: I

      CALL OMP_SET_NUM_THREADS(2)
      A = (/1, 2/)
      T = 4
      P => T

!$OMP PARALLEL PRIVATE(I) COPYIN(A, P)
      I = OMP_GET_THREAD_NUM()
      IF (I .EQ. 0) THEN
        A(1) = 100
        T = 5
      ELSE IF (I .EQ. 1) THEN
        A(2) = 200
      END IF
!$OMP END PARALLEL

!$OMP PARALLEL PRIVATE(I)
      I = OMP_GET_THREAD_NUM()
      IF (I .EQ. 0) THEN
        PRINT *, 'A(2) = ', A(2)
      ELSE IF (I .EQ. 1) THEN
        PRINT *, 'A(1) = ', A(1)
        PRINT *, 'P => ', P
      END IF
!$OMP END PARALLEL

      END PROGRAM MVAR
如果停用動態執行緒機制,則預期輸出為:
A(2) = 2
A(1) = 1
P => 5
or
A(1) = 1
P => 5
A(2) = 2

Example 4: 在此範例中, C 可交互作業變數 NUMVAR 宣告為 THREADPRIVATE。 執行緒 1 對 NUMVAR 的專用副本所做的變更不會影響 主要 執行緒的副本。

Fortran 原始檔
      MODULE M
        USE, INTRINSIC :: ISO_C_BINDING
        INTEGER(C_INT), BIND(C) :: NUMVAR(10)
!$OMP THREADPRIVATE(NUMVAR)
      END MODULE M
      
      PROGRAM P
        USE M
        USE OMP_LIB
        INTERFACE
          SUBROUTINE INIT_NUM() BIND(C)
          END SUBROUTINE INIT_NUM 
          
          SUBROUTINE PRINT_NUM() BIND(C)
          END SUBROUTINE PRINT_NUM 
        END INTERFACE
        INTEGER TNUM
        CALL INIT_NUM()
        
        CALL OMP_SET_NUM_THREADS(2)
        
!$OMP PARALLEL COPYIN(NUMVAR)
        TNUM = OMP_GET_THREAD_NUM()
        IF (TNUM .EQ. 0) THEN
          ! PROCESS NUMVAR
        ELSE IF (TNUM .EQ. 1) THEN
          NUMVAR = NUMVAR * 4
          CALL PRINT_NUM()
          ! PROCESS NUMVAR
        END IF
!$OMP END PARALLEL
        CALL PRINT_NUM()
      END PROGRAM P
C source file
#include <stdio.h>
extern int numvar[10];
#pragma omp threadprivate(numvar)

void init_num(){ 
  for (int i = 0; i < 10; ++ i)    
    numvar[i] = i * i;
}

void print_num(){
  for (int i = 0; i < 10; ++ i)    
    printf("%d ", numvar[i]);
  printf("\n");
}
此程式的預期輸出為:
0 4 16 36 64 100 144 196 256 324
0 1 4 9 16 25 36 49 64 81