前へ | 次へ | 目次 | 索引 |
Alphaシステムでサポートされるページ・サイズを確認するには,$GETSYIシステム・サービスを使用します。 例 5-6 は,このシステム・サービスを使用して実行時にページ・サイズを確認する方法を示しています。
例 5-6 CPU固有のページ・サイズを確認するための$GETSYIシステム・サービスの使用 |
---|
#include <ssdef.h> #include <stdio.h> #include <stsdef.h> #include <descrip.h> #include <dvidef.h> #include <rms.h> #include <secdef.h> #include <syidef.h> /* defines page size item code symbol */ struct itm { /* define item list */ short int buflen; /* length in bytes of return value buffer */ short int item_code; /* item code */ long bufadr; /* address of return value buffer */ long retlenadr; /* address of return value length buffer */ } itmlst[2]; long cpu_pagesize; long cpu_pagesize_len; main( argc, argv ) int argc; char *argv[]; { int status = 0; itmlst[0].buflen = 4; /* page size requires 4 bytes */ itmlst[0].item_code = SYI$_PAGE_SIZE; /* page size item code */ itmlst[0].bufadr = &cpu_pagesize; /* address of ret_val buffer */ itmlst[0].retlenadr = &cpu_pagesize_len; /* addr of length of ret_val */ itmlst[1].buflen = 0; itmlst[1].item_code = 0; /* Terminate item list with longword of 0 */ status = sys$getsyiw( 0, 0, 0, &itmlst, 0, 0, 0 ); if( status & STS$M_SUCCESS ) { printf("getsyi succeeds, page size = %d\n",cpu_pagesize); exit( status ); } else { printf("getsyi fails\n"); exit( status ); } } |
5.5 メモリをワーキング・セットとしてロックする操作
$LKWSETシステム・サービスは,VAXシステムでもAlphaシステムでも同様に,アドレス範囲として inadr 引数に指定したページ範囲をワーキング・セットとしてロックします。このシステム・サービスは必要に応じて,アドレスをCPU固有のページ境界に調整します。
しかし,Alpha命令は完全な仮想アドレスを指定できないため,Alphaイメージはプロシージャ記述子に対するポインタを通じて,間接的にプロシージャとデータを参照しなければなりません。プロシージャ記述子には,実際のコード・アドレスも含めて,プロシージャに関する情報が格納されます。プロシージャ記述子とデータに対するこれらのポインタは,リンケージ・セクションと呼ぶ新しいプログラム・セクションに収集されます。
Alphaシステムでは,単にコード・セクションをメモリにロックするだけでは性能を向上するのに不十分です。関連するリンケージ・セクションもワーキング・セットとしてロックしなければなりません。
リンケージ・セクションをメモリ内でロックするには,リンケージ・セクションの先頭アドレスと末尾アドレスを判断し,$LKWSETシステム・サービスを呼び出すときに,inadr 引数の値としてこれらのアドレスを指定しなければなりません。
この章では,共有データの整合性を維持するのに必要な同期メカニズムについて説明します。たとえば,ある種のVAX命令で保証されている不可分性などについて説明します。
6.1 概要
アプリケーションで複数の実行スレッドを使用しており,これらのスレッドが同じデータをアクセスする場合には,Alphaシステムで共有データの整合性を保護するために,アプリケーションに明示的な同期メカニズムを追加しなければなりません。正しく同期をとらなかった場合には,1つのアプリケーション・スレッドによって開始されたデータ・アクセスが,別のスレッドによって同時に開始されたアクセスを妨害する可能性があり,その結果,データは予測できない状態になる可能性があります。
VAXシステムでは,必要とされる同期のレベルは実行スレッドの関係に応じて異なります。次に示すいくつかの場合は,同期について考慮しなければなりません。
ASTスレッドはアプリケーションによって開始されますが,オペレーティング・システムによって開始されることもあります。たとえば,オペレーティング・システムはASTを使用して状態を入出力状態ブロックに書き込みます。また,オペレーティング・システムではASTを使用して,指定したユーザ・バッファへのバッファを介した読み込み操作を終了します。
VAXシステムでは,マルチプロセッサ・システムの並列処理機能を利用するアプリケーションは常に,ロックやセマフォ,インターロック命令などの明示的な同期メカニズムを準備することにより,共有データを保護しなければなりません。しかし,ユニプロセッサ・システムで複数のスレッドを使用するアプリケーションは,明示的に共有データを保護しない可能性があります。これらのアプリケーションは,VAXユニプロセッサ・システムで実行されるアプリケーションのスレッド間の同期を保証するVAXアーキテクチャの機能によって提供される,暗黙の保護に依存している可能性があります( 第 6.1.1 項 を参照)。
たとえば,複数のスレッドが重要なコード領域をアクセスするときに,アクセスの同期をとるためにセマフォ変数を使用するアプリケーションは,不可分な操作によってインクリメントされるセマフォを必要とします。VAXシステムでは,このような不可分な操作はVAXアーキテクチャによって保証されています。
Alphaアーキテクチャでは,VAXアーキテクチャと同じように同期がとられるという保証はありません。Alphaシステムでは,このセマフォへのアクセスや,複数の実行スレッドがアクセスできるデータへのアクセスは,明示的に同期をとらなければなりません。VAXシステムの場合と同じ保護を実現するために使用できる Alphaアーキテクチャの機能については,第 6.1.2 項 を参照してください。
6.1.1 不可分性を保証するVAXアーキテクチャの機能
VAXアーキテクチャの次の機能は,ユニプロセッサ・システムで実行される複数の実行スレッド間で同期を保証します(ただしVAXアーキテクチャは,マルチプロセッサ・システムに対してはこのような不可分性を保証していません)。
VAXシステムとの互換性を維持するために,Alphaアーキテクチャでは,リード/ライト(読み込み/書き込み)操作が不可分な方法で実行されることを保証する,1組の命令を定義しています。これらの命令についての説明と,高級言語で作成されたプログラムでこの機能を使用した場合に,Alphaシステムのコンパイラがどのような操作を実行するかについては,第 6.1.2 項 を参照してください。
しかし,VAXシステムでも,VAX命令の不可分性に暗黙に依存することは望ましくありません。VAX システムのコンパイラは,インクリメント操作 (x = x + 1)のような不可分な命令が記述されている場合でも,最適化のためにこのような命令を実現しない可能性があります。
このようにメモリ・アクセスの粒度が変更された結果,どのタイプのデータを共有するかについても考慮しなければなりません。VAXシステムでは,共有されるバイト・サイズまたはワード・サイズのデータは個別に操作できます。Alphaシステムでは,バイト・サイズまたはワード・サイズの項目を含むロングワードまたはクォドワード全体を操作しなければなりません。したがって,明示的に共有されるデータに隣接しているという理由だけで,隣接データも暗黙のうちに共有されることになります。
コンパイラは 第 6.1.2 項 で説明するAlpha命令を使用して,バイト・サイズおよびワード・サイズのデータの整合性を保証します。
VAXシステムとの互換性を維持するために,Alphaアーキテクチャでは,システム内のすべてのプロセッサから見て,読み込み/書き込み操作が指定した順に実行されるようにする命令をサポートします。この命令についての説明と,高級言語でこの命令をどのように使用するかについての説明は,第 6.1.2 項 を参照してください。この同期をとるために Alphaアーキテクチャが提供する機能についての説明と,高級言語プログラムでこの機能を利用する際に,Alphaシステムのコンパイラがどのような操作を実行するかについての説明は,第 6.3 節 を参照してください。
VAXアーキテクチャの不可分な機能との互換性を維持するために,Alphaアーキテクチャでは2つのメカニズムを定義しています。
Load-locked/Store-conditional命令を使用することにより,Alphaシステムのコンパイラはバイト・サイズおよびワード・サイズのデータに対して不可分なアクセスを実現できます。さらに,Alphaシステムのコンパイラでは,volatile 属性によって宣言されたバイト・サイズおよびワード・サイズのデータをアクセスするときに,Load-locked/Store-conditional命令を生成できます (Alphaアーキテクチャでは,ロングワード・サイズとクォドワード・サイズのデータの不可分なロード/ストア操作は準備されています)。
アプリケーションで同期が保証されると仮定している部分を検出するための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 例 6-1での不可分性の仮定
このような不可分性への依存を修正するには,次の処理を実行してください。
たとえば,例 6-1 では,Cのインクリメント演算子(flag++)によって実行されるインクリメント操作のかわりに,DEC C for OpenVMS Alphaシステムがサポートする不可分性に関する組み込み機能(__ADD_ATOMIC_LONG(&flag,1,0)) を使用してください。詳しい例については 例 6-2 を参照してください。
共有変数を不可分性に関する組み込み機能によって保護するには,これらの変数はアラインされたロングワードまたはアラインされたクォドワードでなければなりません。
例 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 に示した番号に対応しています。
前へ | 次へ | 目次 | 索引 |