OpenVMS AXP
オペレーティング・システム
OpenVMS AXP オペレーティング・システムへの移行:
再コンパイルと再リンク


前へ 次へ 目次 索引


2.4 ページ・サイズの実行時確認

AXPシステムでサポートされるページ・サイズを確認するには,$GETSYIシステム・サービスを使用します。 例 2-6 は,このシステム・サービスを使用して実行時にページ・サイズを確認する方法を示しています。

例 2-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); 
     } 
} 

2.5 メモリをワーキング・セットとしてロックする操作

$LKWSETシステム・サービスは,VAXシステムでもAXPシステムでも同様に,アドレス範囲として inadr 引数に指定したページ範囲をワーキング・セットとしてロックします。このシステム・サービスは必要に応じて,アドレスをCPU固有のページ境界に調整します。

しかし,Alpha AXP命令は完全な仮想アドレスを指定できないため,AXPイメージはプロシージャ記述子に対するポインタを通じて,間接的にプロシージャとデータを参照しなければなりません。プロシージャ記述子には,実際のコード・アドレスも含めて,プロシージャに関する情報が格納されます。プロシージャ記述子とデータに対するこれらのポインタは,リンケージ・セクションと呼ぶ新しいプログラム・セクションに収集されます。

対処方法

AXPシステムでは,単にコード・セクションをメモリにロックするだけでは性能を向上するのに不十分です。関連するリンケージ・セクションもワーキング・セットとしてロックしなければなりません。

リンケージ・セクションをメモリ内でロックするには,リンケージ・セクションの先頭アドレスと末尾アドレスを判断し,$LKWSETシステム・サービスを呼び出すときに,inadr 引数の値としてこれらのアドレスを指定しなければなりません。


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

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

3.1 概要

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

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

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

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

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

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

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

3.1.2 OpenVMS AXPの互換性機能

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

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

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

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

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

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

図 3-1 同期に関する判断


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

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

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

#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; 
} 

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

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

図 3-2 例 3-1での不可分性の仮定


対処方法

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

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

例 3-2 例 3-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; 
} 

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

  1. DEC C for OpenVMS AXPシステムの不可分性に関する組み込み機能を使用するには,builtins.hヘッダ・ファイルをインクルードしなければなりません。

  2. このバージョンでは,変数 flag はロングワードとして宣言されているため,不可分なアクセスが可能です(不可分性に関する組み込み機能を使用するには,変数をこのように宣言しなければなりません)。

  3. インクリメント操作は不可分性に関する組み込み機能を使用して実行されます。


前へ 次へ 目次 索引