日本-日本語

製品  >  ソフトウェア  >  OpenVMS  >  マニュアル

OpenVMS マニュアル


≫ 

OpenVMS V8.3
ライブラリ

タイトルページ
目次
まえがき
第 1 章:移行プロセスの概要
第 2 章:移行方法の選択
第 3 章:アプリケーションの移行
第 4 章:再コンパイルと再リンクの概要
第 5 章:ページ・サイズの拡大に対するアプリケーションの対応
第 6 章:共有データの整合性の維持
第 7 章:アプリケーション・データ宣言の移植性の確認
第 8 章:アプリケーション内の条件処理コードの確認
第 9 章:アプリケーションのトランスレート
第 10 章: ネイティブなイメージとトランスレートされたイメージの間の相互操作性の確認
第 11 章:OpenVMS Alpha コンパイラ
付録 A :アプリケーション評価チェックリスト
用語集
索引
PDF
OpenVMS ホーム
OpenVMS Alpha オペレーティング・システム | HPE 日本(日本ヒューレット・パッカード株式会社)

OpenVMS Alpha
オペレーティング・システム
OpenVMS VAX から OpenVMS Alpha へのアプリケーションの移行


目次 索引

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

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

6.1 概要

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

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

  • 1つのプロセス内で実行される複数のスレッド。たとえば,非同期システム・トラップ (AST)スレッドによってメイン・スレッドが割り込まれる可能性があります。
    ASTスレッドはアプリケーションによって開始されますが,オペレーティング・システムによって開始されることもあります。たとえば,オペレーティング・システムはASTを使用して状態を入出力状態ブロックに書き込みます。また,オペレーティング・システムではASTを使用して,指定したユーザ・バッファへのバッファを介した読み込み操作を終了します。

  • 1つのプロセッサ上で複数のプロセスが実行されているとき,ある共通のグローバル・セクションにアクセスする,これらのプロセスによるスレッド

  • 複数のプロセッサ上で複数のプロセスが並行に実行されているとき,ある共通のグローバル・セクションにアクセスする,これらのプロセスによるスレッド

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

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

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

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

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

  • 命令の不可分性---VAXアーキテクチャによって定義されている多くの命令は,単一プロセッサで実行される複数のアプリケーション・スレッドの観点から見ると,1つの割り込み不可能なシーケンス(不可分な操作と呼ぶ)としてリード・モディファイ・ライト(読み込み/変更/書き込み)操作を実行できます。しかし,Alphaアーキテクチャでは,このような命令はサポートされません。VAXシステムで不可分な操作として実行できる操作は, Alphaシステムでは一連の命令として実行しなければならず,その途中で割り込みが発生する可能性があり,その結果,データは予測できない状態になる可能性があります。
    たとえば,VAX Increment Long (INCL)命令は指定されたロングワードの内容をフェッチし,その値をインクリメントし,値を元のロングワードに格納します。これらの操作は割り込み不可能な方法で実行されます。しかし,Alphaシステムでは,各ステップを別々の命令で実行しなければなりません。
    VAXシステムとの互換性を維持するために,Alphaアーキテクチャでは,リード/ライト(読み込み/書き込み)操作が不可分な方法で実行されることを保証する, 1組の命令を定義しています。これらの命令についての説明と,高級言語で作成されたプログラムでこの機能を使用した場合に,Alphaシステムのコンパイラがどのような操作を実行するかについては, 第 6.1.2 項 を参照してください。
    しかし,VAXシステムでも,VAX命令の不可分性に暗黙に依存することは望ましくありません。VAX システムのコンパイラは,インクリメント操作 ( x = x + 1)のような不可分な命令が記述されている場合でも,最適化のためにこのような命令を実現しない可能性があります。

  • メモリ・アクセスの粒度---VAXアーキテクチャは,バイト・サイズのデータとワード・サイズのデータを1つの割り込み不可能な操作で処理できる命令をサポートします(VAXアーキテクチャは他のサイズのデータも処理できるような命令をサポートします)。 Alphaアーキテクチャでは,ロングワード・サイズとクォドワード・サイズのデータを処理する命令のみをサポートします。Alphaシステムでバイト・サイズおよびワード・サイズのデータを処理するには,複数の命令が必要です。つまり,バイトまたはワードを格納したロングワードまたはクォドワードをフェッチし,不要なバイトをマスクしなければならず,処理の対象となるバイトまたはワードを操作した後,ロングワードまたはクォドワード全体を格納しなければなりません。このシーケンスは割り込み可能であるため,バイト・データとワード・データに対する操作は,VAXシステムでは不可分な操作ですが,Alphaシステムでは不可分な操作ではありません。
    このようにメモリ・アクセスの粒度が変更された結果,どのタイプのデータを共有するかについても考慮しなければなりません。VAXシステムでは,共有されるバイト・サイズまたはワード・サイズのデータは個別に操作できます。Alphaシステムでは,バイト・サイズまたはワード・サイズの項目を含むロングワードまたはクォドワード全体を操作しなければなりません。したがって,明示的に共有されるデータに隣接しているという理由だけで,隣接データも暗黙のうちに共有されることになります。
    コンパイラは 第 6.1.2 項 で説明するAlpha命令を使用して,バイト・サイズおよびワード・サイズのデータの整合性を保証します。

  • 読み込み/書き込みの順序---VAXユニプロセッサおよびマルチプロセッサ・システムでは,一連の書き込み操作と読み込み操作は,すべてのタイプの外部実行スレッドから見て,要求した順序と同じ順序で実行されます。Alphaユニプロセッサ・システムでも,読み込み操作と書き込み操作の順序はユニプロセッサで実行される単一プロセス,または複数プロセス内で実行される複数の実行スレッドに対して,同期がとられているように見えます。しかし, Alphaマルチプロセッサ・システムで同時に実行されるスレッドから書き込み操作を確認するには,明示的に同期をとることが必要です。
    VAXシステムとの互換性を維持するために,Alphaアーキテクチャでは,システム内のすべてのプロセッサから見て,読み込み/書き込み操作が指定した順に実行されるようにする命令をサポートします。この命令についての説明と,高級言語でこの命令をどのように使用するかについての説明は, 第 6.1.2 項 を参照してください。この同期をとるために Alphaアーキテクチャが提供する機能についての説明と,高級言語プログラムでこの機能を利用する際に,Alphaシステムのコンパイラがどのような操作を実行するかについての説明は, 第 6.3 節 を参照してください。



6.1.2 Alphaの互換性機能

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

  • Load-locked/Store-conditional命令---Alpha命令セットには, Load-locked(LDxL)とStore-conditional (STxC)という名前の 1組の命令があり,ロック・ビットをセットおよびテストすることにより,不可分なロード/ストア操作を可能にします。これらの命令についての詳しい説明は,『Alpha Architecture Reference Manual』を参照してください。
    Load-locked/Store-conditional命令を使用することにより,Alphaシステムのコンパイラはバイト・サイズおよびワード・サイズのデータに対して不可分なアクセスを実現できます。さらに,Alphaシステムのコンパイラでは,volatile 属性によって宣言されたバイト・サイズおよびワード・サイズのデータをアクセスするときに,Load-locked/Store-conditional命令を生成できます (Alphaアーキテクチャでは,ロングワード・サイズとクォドワード・サイズのデータの不可分なロード/ストア操作は準備されています)。

  • メモリ・バリア---Alpha命令セットには,マルチプロセッサ・システムで複数のプロセッサで実行される複数のスレッドが要求した読み込み/書き込み操作が要求した順に実行されているかのように見えるようにするための命令が準備されています。この命令はメモリ・バリアと呼ばれ,複数の実行スレッドから見て,前のすべてのロード/ストア命令がメモリ・アクセスを完了するまで,後続のロード/ストア命令がメモリをアクセスしないことを保証します。



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

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

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

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

  • 共有データに対して実行される操作は,他の実行スレッドの観点から見たときに不可分ですか。

  • 関係するデータ型に対する不可分な操作を実行できますか。

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

図 6-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 不可分性の仮定


対処方法

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

  • データがアクセスされている間,$SETASTシステム・サービスを使用してASTの実行要求を禁止し,アクセスが終了した後で実行要求を可能にします。

  • コンパイラ・メカニズムを使用して,データを明示的に保護してください。たとえば,DEC C for OpenVMS Alphaシステムは不可分性に関する組み込み機能をサポートします。さらに,このデータへのアクセスの同期をとるために他のメカニズムを使用できます。たとえば,$ENQシステム・サービスを使用したり(マルチプロセッサ・システムで実行される複数のスレッドによってアクセスされるデータの場合),また, LIB$BBCCIやLIB$BBSSIなどのランタイム・ライブラリ・ルーチンやインターロック・キュー・ルーチンを使用することもできます。
    たとえば, 例 6-1 では,Cのインクリメント演算子(flag++)によって実行されるインクリメント操作のかわりに,DEC C for OpenVMS Alphaシステムがサポートする不可分性に関する組み込み機能(__ADD_ATOMIC_LONG(&flag,1,0)) を使用してください。詳しい例については 例 6-2 を参照してください。
    共有変数を不可分性に関する組み込み機能によって保護するには,これらの変数はアラインされたロングワードまたはアラインされたクォドワードでなければなりません。

  • バイト・サイズまたはワード・サイズのデータをロングワードまたはクォドワードに変更できない場合には,データをアクセスするときにコンパイラが使用する粒度を変更してください。Alphaシステムの多くのコンパイラでは,特定のデータをアクセスするときやモジュール全体を処理するときに使用する粒度を指定できます。しかし,バイト粒度とワード粒度を指定すると,アプリケーションの性能が低下する可能性があります。

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

例 6-2 上記のサンプル・コードの同期バージョン

#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 に示した番号に対応しています。


目次 索引

印刷用画面へ
プライバシー 本サイト利用時の合意事項