[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ] [ DOC Home ]

6 共有データの整合性の維持

この章では, 共有データの整合性を維持するのに必要な同期メカニズムについて説明します。 たとえば,ある種のVAX命令で保証されている不可分性などについて説明します。


6.1 概要

アプリケーションで複数の実行スレッドを使用しており, これらのスレッドが同じデータをアクセスする場合には, Alphaシステムで共有データの整合性を保護するために, アプリケーションに明示的な同期メカニズムを追加しなければなりません。 正しく同期をとらなかった場合には, 1つのアプリケーション・スレッドによって開始されたデータ・アクセスが, 別のスレッドによって同時に開始されたアクセスを妨害する可能性があり, その結果,データは予測できない状態になる可能性があります。

VAXシステムでは,必要とされる同期のレベルは実行スレッドの関係に応じて異なります。 次に示すいくつかの場合は,同期について考慮しなければなりません。

VAXシステムでは, マルチプロセッサ・システムの並列処理機能を利用するアプリケーションは常に, ロックやセマフォ, インターロック命令などの明示的な同期メカニズムを準備することにより, 共有データを保護しなければなりません。しかし, ユニプロセッサ・システムで複数のスレッドを使用するアプリケーションは, 明示的に共有データを保護しない可能性があります。これらのアプリケーションは, VAXユニプロセッサ・システムで実行されるアプリケーションのスレッド間の同期を保証する VAXアーキテクチャの機能によって提供される, 暗黙の保護に依存している可能性があります (第6.1.1項を参照)。

たとえば,複数のスレッドが重要なコード領域をアクセスするときに, アクセスの同期をとるためにセマフォ変数を使用するアプリケーションは, 不可分な操作によってインクリメントされるセマフォを必要とします。 VAXシステムでは,このような不可分な操作はVAXアーキテクチャによって保証されています。

Alphaアーキテクチャでは, VAXアーキテクチャと同じように同期がとられるという保証はありません。 Alphaシステムでは,このセマフォへのアクセスや, 複数の実行スレッドがアクセスできるデータへのアクセスは, 明示的に同期をとらなければなりません。 VAXシステムの場合と同じ保護を実現するために使用できる Alphaアーキテクチャの機能については, 第6.1.2項を参照してください。


6.1.1  不可分性を保証するVAXアーキテクチャの機能

VAXアーキテクチャの次の機能は, ユニプロセッサ・システムで実行される複数の実行スレッド間で同期を保証します (ただしVAXアーキテクチャは, マルチプロセッサ・システムに対してはこのような不可分性を保証していません)。


6.1.2 Alphaの互換性機能

VAXアーキテクチャの不可分な機能との互換性を維持するために, Alphaアーキテクチャでは2つのメカニズムを定義しています。


6.2  アプリケーションにおける不可分性への依存の検出

アプリケーションで同期が保証されると仮定している部分を検出するための 1つの方法として,複数の実行スレッド間で共有されるデータを識別し, 各スレッドからのデータ・アクセスを確認する方法があります。 共有データを検出する場合には,意図的に共有されるデータだけでなく, 暗黙のうちに共有されるデータも検出しなければなりません。 暗黙のうちに共有されるデータとは, 複数の実行スレッドによってアクセスされるデータに近接しているために共有されるデータです。 たとえば,$QIO,$ENQ, $GETJPIなどのシステム・サービスの結果としてオペレーティング・システムが生成した ASTによって書き込まれるデータは,このような暗黙のうちに共有されるデータです。

Alphaシステムのコンパイラはある状況では, 省略時の設定でクォドワード命令を使用するため, 共有データが格納されているクォドワードと同じクォドワード内のすべてのデータは暗黙のうちに共有される可能性があります。 たとえば,コンパイラは自然な境界にアラインされていないデータをアクセスするためにクォドワード命令を使用します (アドレスがデータ・サイズで割り切れる場合には, データは自然にアラインされています。詳しくは 第7章を参照してください。 コンパイラは省略時の設定により,宣言されたデータを自然な境界にアラインします)。

データ・アクセスを調べる場合には, 別のスレッドが処理中の状態のデータを確認する可能性がないかどうかを判断し, このような可能性がある場合には, それがアプリケーションにとって重要な問題であるかどうかを判断してください。 場合によっては, 共有データの値が正確であることがそれほど重要でない場合もあります。たとえば, アプリケーションが変数の相対値だけを必要とする場合には, 正確な値は必要ありません。これらを調べるために,次の事項をチェックしてください。

図 6-1はこの判断を下す処理を示しています。

図 6-1 同期に関する判断 :(クリックで表示)


6.2.1 明示的に共有されるデータの保護

例 6-1のプログラムは, VAXアプリケーションで不可分性が保証されると仮定した部分を簡単に示しています。 このプログラムでは,flag という変数を使用しており, ASTスレッドはこの変数を通じてメイン処理スレッドと通信します。この例では, カウンタ変数が前もって定義した値に到達するまで, メイン処理ループは処理を継続します。プログラムは flag を最大値に設定するAST割り込みをキューに登録し, 処理ループを終了します。

例 6-1  ASTスレッドを含むプログラムにおける不可分な処理への依存

     #include <ssdef.h>

     #include <descrip.h>

     #define MAX_FLAG_VAL 1500

     int    ast_rout();
     long  time_val[2];
     short int    flag;    /* accessed by main and AST threads */

     main( )
     {
          int      status = 0;
          static  $DESCRIPTOR(time_desc, "0 ::1");

          /*  changes ASCII time value to binary value  */

          status = SYS$BINTIM(&time_desc, &time_val);

          if ( status != SS$_NORMAL )
          {
             printf("bintim failure\n");
             exit( status );
          }

          /*  Set timer, queue ast */

          status = SYS$SETIMR( 0, &time_val, ast_rout, 0, 0 );

          if ( status != SS$_NORMAL )
          {
             printf("setimr failure\n");
             exit( status );
          }

          flag = 0;   /* loop until flag = MAX_FLAG_VAL */
          while( flag < MAX_FLAG_VAL )
          {
                printf("main thread processing (flag = %d)\n",flag);
                flag++;
          }
          printf("Done\n");
     }

     ast_rout()     /*  sets flag to maximum value to stop processing */
     {
           flag = MAX_FLAG_VAL;
     }
例 6-1では,flag という名前の変数がメイン実行スレッドとASTスレッドの間で明示的に共有されます。 このプログラムでは, この変数の整合性を保護するために同期メカニズムを使用していません。つまり, インクリメント操作が不可分な方法で実行されることを暗黙のうちに仮定しています。

Alphaシステムでは,このプログラムは常に VAXシステムと同じように動作するわけではありません。これは, 図 6-2に示すように,新しい値をメモリに格納する前に, メイン実行スレッドがインクリメント操作の途中で ASTスレッドによって割り込まれる可能性があるからです(実際のアプリケーションでは, 多くのASTスレッドによって割り込みが発生する可能性がもっと高くなります)。 この例では, ASTスレッドはインクリメント操作が終了する前にこの操作に割り込みをかけ, 変数の値を最大値に設定します。しかし,制御がメイン・スレッドに戻された後, インクリメント操作は終了し,ASTスレッドの値が上書きされます。 ループ・テストを実行すると,値は最大値でないため,処理ループは継続されます。

図 6-2 例 6-1 での不可分性の仮定 :(クリックで表示)

対処方法

このような不可分性への依存を修正するには,次の処理を実行してください。

例 6-2は, 例 6-1に示したプログラムでこれらの変更を行う方法を示しています。

例 6-2  例 6-1の同期バージョン

     #include <ssdef.h>
     #include <descrip.h>
     #include <builtins.h>  【1】

     #define MAX_FLAG_VAL  1500
     int    ast_rout();
     long  time_val[2];
     int 【2】       flag;    /* accessed by mainline and AST threads */

     main( )
     {
          int      status = 0;
          static  $DESCRIPTOR(time_desc, "0 ::1");
     
          /*  changes ASCII time value to binary value  */

          status = SYS$BINTIM(&time_desc, &time_val);

          if ( status != SS$_NORMAL )
          {
             printf("bintim failure\n");
             exit( status );
          }

          /*  Set timer, queue ast */

          status = SYS$SETIMR( 0, &time_val, ast_rout, 0, 0 );

          if ( status != SS$_NORMAL )
          {
             printf("setimr failure\n");
             exit( status );
          }
          flag = 0;
          while( flag < MAX_FLAG_VAL )   /* perform work until flag set to zero */
          {
               printf("mainline thread processing (flag = %d)\n",flag);
               __ADD_ATOMIC_LONG(&flag,1,0); 【3】
          }
          printf("Done\n");
     }

     ast_rout()     /*  sets flag to maximum value to stop processing */
     {
          flag = MAX_FLAG_VAL;
     }

次のリストの各項目は 例 6-2に示した番号に対応しています。

【1】 DEC C for OpenVMS Alphaシステムの不可分性に関する組み込み機能を使用するには, builtins.hヘッダ・ファイルをインクルードしなければなりません。
【2】 このバージョンでは,変数 flag はロングワードとして宣言されているため, 不可分なアクセスが可能です(不可分性に関する組み込み機能を使用するには, 変数をこのように宣言しなければなりません)。
【3】 インクリメント操作は不可分性に関する組み込み機能を使用して実行されます。


6.2.2 無意識に共有されるデータの保護

例 6-1では, 2つのスレッドはどちらも同じ変数をアクセスします。しかし,Alphaシステムでは, 暗黙のうちに共有される変数に対してアプリケーションで不可分性を持たせることが可能です。 この例では,2つの変数はロングワードまたはクォドワードの境界内で物理的に隣接しています。 VAXシステムでは,各変数は個別に処理できます。 Alphaシステムでは,ロングワード・データとクォドワード・データのみ, 不可分な読み込み操作と書き込み操作がサポートされるため, 処理の対象となるバイトを変更する前に, ロングワード全体をフェッチしなければなりません (データ・アクセス粒度の変更についての詳しい説明は, 第7章を参照してください)。

この問題を示すために,例 6-1 のプログラムを変更したバージョンについて考えてみましょう。 このバージョンでは,メイン・スレッドと ASTスレッドはそれぞれデータ構造体で宣言された別々のカウンタ変数をインクリメントします。 カウンタ変数は次の文によって宣言されます。

     struct {
     short int     flag;
     short int ast_flag;
     };
メイン・スレッドとASTスレッドがどちらも, 処理の対象となるワードを同時に変更しようとした場合には, 2つの操作が実行されるタイミングに応じて,結果は予想できなくなります。

対処方法

同期に関するこの問題を解決するには,次の処理を実行してください。


6.3 読み込み/書き込み操作の同期

VAXマルチプロセシング・システムは従来,マルチプロセシング・システム内の 1つのプロセッサが複数のデータを書き込むときに, これらのデータが書き込まれた順序と同じ順序で, 他のすべてのプロセッサから確認できるように設計されていました。たとえば, CPU Aがデータ・バッファを書き込み(図 6-3で Xによって表現されるもの),その後でフラグを書き込んだ場合 (図 6-3でYによって表現されるもの), CPU Bはフラグの値を確認することにより, データ・バッファが変更されたことを判断できます。

Alphaシステムでは,メモリ・サブシステム全体の性能を向上するために, メモリとの間の読み込み操作および書き込み操作の順序が変更される可能性があります。 単一プロセッサで実行されるプロセスの場合には, そのプロセッサからの書き込み操作は要求された順に読み込み可能になることを仮定できます。 しかし,マルチプロセッサ・アプリケーションの場合には, メモリに対する書き込み操作の結果がシステム全体から確認できるようになる順序を, 前もって判断できません。つまり,CPU Aによって実行される書き込み操作は, 実際に書き込まれた順序とは異なる順序でCPU Bから見える場合もあります。

図 6-3はこの問題を示しています。CPU Aは Xに対する書き込み操作を要求し,その後,Yに対する書き込み操作を要求します。 CPU BはYからの読み込み操作を要求し,Yの新しい値を確認し, Xの読み込み操作を開始します。Xの新しい値がまだメモリに書き込まれていない場合には, CPU Bは前の値を読み込みます。この結果,CPU AとCPU Bで実行され るプロシージャが依存するトークン受け渡しプロトコルは正しく機能しなくなります。 CPU Aはデータを書き込み,フラグ・ビットをセットできますが,CPU Bは, データが実際に書き込まれる前にフラグ・ビットがセットされていることを確認する可能性があり, その結果,誤ったメモリの内容を使用してしまいます。

図 6-3 Alphaシステムでの読み込み/書き込み操作の順序 :(クリックで表示)

対処方法

並列に実行され,読み込み/書き込みの順序に依存するプログラムは, Alphaシステムで正しく実行するために何らかの設計変更が必要です。 アプリケーションに応じて,次の方法を使用してください。


6.4  トランスレートされたイメージの不可分性の保証

VESTコマンドの/PRESERVE修飾子は, VAXシステムで提供されるのと同じ不可分性を保証して, Alphaシステムでトランスレートされた VAXイメージを実行できるようにするためのキーワードを受け付けます。 /PRESERVE修飾子のキーワードは複数のタイプの不可分性保護機能を提供します。 ただし,これらの/PRESERVE修飾子のキーワードを指定すると, アプリケーションの性能が低下する可能性があります (/PRESERVE修飾子の指定についての詳しい説明は, 『DECmigrate for OpenVMS AXP Systems Translating Images』を参照してください)。

VAXシステムでVAX命令が不可分な方法で実行できる操作を, トランスレートされたイメージでもできるようにするには,/PRESERVE修飾子に対して INSTRUCTION_ATOMICITYキーワードを指定します。

ロングワードまたはクォドワードに格納された隣接バイトを同時に更新し, これらの各バイトが相互に妨害しないようにするには,/PRESERVE修飾子に対して MEMORY_ATOMICITYキーワードを指定します。

読み込み/書き込み操作が実行される順序が要求した順序と同じ順序で実行されるように見えるようにするには, /PRESERVE修飾子に対してREAD_WRITE_ORDERINGキーワードを指定します。


[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ] [ DOC Home ]