スレッド

Microsoft 固有の仕様

thread 拡張ストレージ クラス修飾子は、スレッド ローカル変数を宣言するために使用されます。 C++11 における移植可能な等価のものとして、移植可能なコード用に thread_local ストレージ クラス指定子を使用します。 Windows の thread_local__declspec(thread) を使用して実装されます。

構文

__declspec(thread)宣言子

解説

スレッド ローカル ストレージ (TLS) は、特定のマルチスレッド プロセスの各スレッドが、スレッド固有のデータを格納するための場所を割り当てる機能です。 標準のマルチスレッド プログラムでは、データは特定のプロセスのすべてのスレッド間で共有されますが、スレッド ローカル ストレージはスレッドごとのデータを割り当てるための機能です。 スレッドの詳細については、マルチスレッドに関するトピックを参照してください。

スレッド ローカル変数の宣言では、拡張属性構文 を使用し、__declspec キーワードを thread キーワードと共に使用する必要があります。 たとえば、次に示すコードは、整数型のスレッド ローカル変数を宣言して特定の値に初期化します。

__declspec( thread ) int tls_i = 1;

動的に読み込まれたライブラリでスレッド ローカル変数を使用する場合は、スレッド ローカル変数が正しく初期化されない原因となる可能性がある要因に注意する必要があります。

  1. 変数が関数呼び出し (コンストラクターを含む) で初期化されている場合、この関数は、バイナリ/DLL がプロセスに読み込まれる原因となるスレッドと、バイナリ/DLL が読み込まれた後に開始されたスレッドに対してのみ呼び出されます。 DLL の読み込み時に既に実行されている他のスレッドに対して、初期化関数は呼び出されません。 動的初期化は DLL_THREAD_ATTACH の DllMain 呼び出しで行われますが、スレッドの開始時に DLL をプロセスに含めなかった場合、DLL はそのメッセージを取得しません。

  2. 定数値を使用して静的に初期化されるスレッド ローカル変数は、通常、すべてのスレッドで適切に初期化されます。 ただし、2017 年 12 月時点で、Microsoft C++ コンパイラでは、constexpr 変数が静的な初期化ではなく動的な初期化を受け取るという既知の適合性の問題があります。

    注: これらの問題はどちらも、コンパイラの今後の更新で修正される予定です。

また、スレッド ローカルのオブジェクトおよび変数を宣言するときは、以下のガイドラインに従う必要があります。

  • thread 属性は、クラスおよびデータの宣言と定義のみに適用できます。thread を関数宣言や関数定義に使用することはできません。

  • thread 属性は、静的ストレージ存続期間のあるデータ項目にのみ指定できます。 これには、グローバルなデータ オブジェクト (staticextern の両方)、ローカルな静的オブジェクト、クラスの静的データ メンバーが含まれます。 thread 属性を使用して自動データ オブジェクトを宣言することはできません。

  • 宣言と定義が同じファイルと別々のファイルのどちらで発生する場合でも、スレッド ローカル オブジェクトの宣言と定義には thread 属性を使用する必要があります。

  • thread 属性を型修飾子として使用することはできません。

  • thread 属性を使用するオブジェクトの宣言は許可されるので、次の 2 つの例は同じ意味になります。

    // declspec_thread_2.cpp
    // compile with: /LD
    __declspec( thread ) class B {
    public:
       int data;
    } BObject;   // BObject declared thread local.
    
    class B2 {
    public:
       int data;
    };
    __declspec( thread ) B2 BObject2;   // BObject2 declared thread local.
    
  • 標準 C では、自分自身への参照を含む式でオブジェクトや変数を初期化できます。ただし、非静的なオブジェクトに限られます。 C++ では、通常、自分自身への参照を含む式でこのようにオブジェクトを動的に初期化できますが、この種の初期化はスレッド ローカル オブジェクトでは許可されません。 次に例を示します。

    // declspec_thread_3.cpp
    // compile with: /LD
    #define Thread __declspec( thread )
    int j = j;   // Okay in C++; C error
    Thread int tls_i = sizeof( tls_i );   // Okay in C and C++
    

    初期化されるオブジェクトが含まれる sizeof 式は、そのオブジェクト自体への参照が発生しないので、C と C++ の両方で有効になります。

Microsoft 固有の仕様はここまで

関連項目

__declspec
キーワード
スレッド ローカル ストレージ (TLS: Thread Local Storage)