日本-日本語
日本HPホーム 製品 & サービス OpenVMS製品情報
≫  お問い合わせ


OpenVMS マニュアル


 

OpenVMS ドキュメント
ライブラリ

タイトルページ
目次
まえがき
第 1 章:はじめに
第 2 章:入出力について
第 3 章:文字/文字列/引数リスト関数
第 4 章:エラー処理とシグナル処理
第 5 章:サブプロセス関数
第 6 章:Curses画面管理関数とマクロ
第 7 章:算術関数
第 8 章:メモリ割り当て関数
第 9 章:システム関数
第 10 章:国際化ソフトウェアの開発
第 11 章:日付/時刻関数
第 12 章:シンボリックリンクとPOSIXパス名
付録 A:各OSバージョンでサポートする関数一覧
付録 B:非標準ヘッダに複製されているプロトタイプ
索引
PDF
OpenVMS ホーム

HP OpenVMS
HP C ランタイム・ライブラリ・リファレンス・マニュアル (上巻)


目次 索引

第 5 章
サブプロセス関数

HP C Run-Time Library (RTL) では, HP C プログラムからサブプロセスを生成するための関数が提供されます。サブプロセスを生成するプロセスをと呼び,生成されるサブプロセスをと呼びます。

親プロセスの内部で子プロセスを生成するには, exec関数 ( execlexecleexecvexecveexeclpexecvp) および vfork関数を使用します。その他にも,親プロセスと子プロセスがプロセス間でデータの読み書きを実行するための関数 ( pipe) や 2 つのプロセスの同期をとるための関数 ( wait) などもあります。この章では,これらの関数の実装の方法と使用方法について説明します。

親プロセスは子プロセスの内部で,同期的または非同期的に HP C プログラムを実行できます。同時に実行できる子プロセスの数は,システムの各ユーザに対して設定されている /PRCLM ユーザ登録クォータによって決定されます。サブプロセスの使用に影響を与える可能性のあるその他のクォータとしては, /ENQLM (キュー・エントリ・リミット),/ASTLM (AST 待ちリミット), /FILLM (オープン・ファイル・リミット) があります。

この章では,サブプロセス関数について説明します。 表 5-1 は, HP C RTL で提供されるすべてのサブプロセス関数を示しています。各関数の詳細については,『HP C ランタイム・ライブラリ・リファレンス・マニュアル (下巻)』「リファレンス・セクション」を参照してください。

表 5-1 サブプロセス関数
関数 説明
子プロセスの生成
system コマンド・プロセッサによって実行される文字列をホスト環境に渡す。
vfork 独立した子プロセスを生成する。
exec 関数
execl,execle,execlp
execv,execve,execvp
子プロセスの内部で起動されるイメージの名前を渡す。
プロセスの同期化
wait wait3 wait4 waitpid 値が子から返されるまで,親プロセスを一時停止する。
プロセス間通信
pipe 親プロセスと子プロセスの間の通信を可能にする。



5.1 HP C での子プロセスの生成

子プロセスは,OpenVMS LIB$SPAWN RTL ルーチンと HP C 関数によって生成されます (LIB$SPAWN の詳細については,『VMS Run-Time Library Routines Volume』を参照してください)。 LIB$SPAWN を使用すると,複数レベルの子プロセスを生成できます。親から生成された子がさらに子を生成することができます。生成できるレベルは,この章の冒頭で説明したユーザ登録クォータで認められている上限値までです。

子プロセスは他の HP C プログラムだけを実行できます。他のネイティブ・モードの OpenVMS 言語は,プロセス間で通信するために HP C の機能を共用しません。プロセス間で通信する場合,他の言語は同じ機能を使用しません。親プロセスは,DCL など,弊社がサポートするコマンド言語インタプリタ (CLI) のもとで実行しなければなりません。親を独立プロセスとして実行したり,ユーザ指定 CLI の制御のもとで実行することはできません。

DECC$DETACHED_CHILD_PROCESS 機能論理名を有効にすると,子プロセスが,サブプロセスではなく,デタッチされたプロセスとして生成されます。この機能のサポートには,制限があります。場合によっては,コンソールが親プロセスと,デタッチされたプロセスで共用できず, execが失敗することがあります。

親プロセスと子プロセスは, 図 5-1 に示すようにメールボックスを通じて通信します。このメールボックスは,子が実行されるコンテキストを転送します。このコンテキスト・メールボックスは,親がオープンしたすべてのファイルの名前やファイル記述子,それらのファイル内での現在の位置など,親から継承する情報を子に渡します。子イメージが終了すると,メールボックスは親によって削除されます。

図 5-1 親プロセスと子プロセスの間の通信リンク


  注意
vfork関数と exec関数によって作成されるメールボックスは一時的なものです。このメールボックスの論理名は VAXC$EXECMBX であり, HP C RTL で使用するために予約されています。

メールボックスは 512 バイトの最大メッセージ・サイズおよび 512 バイトのバッファ・クォータで作成されます。これらの RTL 関数を使用してメールボックスを作成するには,TMPMBX 特権が必要です。 TMPMBX は DCL コマンド PRINT および SUBMIT で必要とされる特権であるため,システムの大部分のユーザはこの特権を保有しています。保有しているシステム特権を確認するには, SHOW PROCESS/PRIVILEGES コマンドを入力します。

これらのメールボックスの属性を変更することはできません。メールボックスの詳細については,『VMS I/O User's Reference Volume』を参照してください。

5.2 exec 関数

子プロセスで HP C イメージを実行するために呼び出すことのできる exec関数は 6 つあります。これらの関数では,戻りアドレスを設定するために vforkがあらかじめ呼び出されていることが必要です。 exec関数は,親プロセスで vforkが呼び出されていない場合,その関数を呼び出します。

vforkが親で呼び出されると, exec関数は親プロセスに戻ります。 vforkexec関数によって呼び出されると, exec関数はその関数自体に戻り,子プロセスが終了するのを待ち,その後で親プロセスを終了します。 exec関数は,親が vforkを呼び出して戻りアドレスを保存しない限り,親プロセスに戻りません。

OpenVMS Version 7.2 で, exec関数は実行可能イメージまたは DCL コマンド・プロシージャを起動するように拡張されました。ファイル拡張が file_name 引数に指定されていない場合は,この関数はまずファイル拡張が .EXE であるファイルを検索し,次にファイル拡張が .COM であるファイルを検索します。同じ名前の実行可能イメージとコマンド・プロシージャの両方が存在する場合は,コマンド・プロシージャを強制的に起動するために, .COM ファイル拡張を指定する必要があります。

DCL コマンド・プロシージャの場合は, exec関数は, P1P2,...パラメータなど, exec呼び出しに指定した最初の 8 つの arg0arg1,... 引数をコマンド・プロシージャに渡します。その場合,大文字と小文字の区別は保持されます。

UNIX ベースのシステムと異なり, HP C RTL の exec関数は,指定された実行可能イメージまたはコマンド・プロシージャが存在するかどうか,またこれらを起動および実行できるがどうかを常に判断できるわけではありません。したがって, exec関数は,子プロセスが指定されたファイルを実行できない場合でも,正常終了したように見えることがあります。

親プロセスへ返される子プロセスの状態は,エラーが発生したことを示します。このエラー・コードは, wait関数ファミリのいずれかの関数を使用することにより検索できます。

  注意
OpenVMS システムの HP C RTL の vfork関数と exec関数は, UNIX システムの場合と異なる方法で動作します。

  • UNIX システムでは, vforkは子プロセスを生成し,親プロセスを一時停止し,親が停止した場所から子プロセスの実行を開始します。

  • OpenVMS システムでは, vforkexec関数で後で使用されるコンテキストを設定しますが,指定されたプログラムを実行するプロセスを開始するのは, vforkではなく, exec関数です。

プログラマの場合,次の重要な相違点に注意してください。

  • OpenVMS システムでは, vfork関数の呼び出しと exec関数の呼び出しの間のコードは親プロセスで実行されます。
    UNIX システムでは,このコードは子プロセスで実行されます。

  • OpenVMS システムでは, exec関数が呼び出されたポイントで,子プロセスはオープンされているファイルの記述子などを継承します。
    UNIX システムでは,この継承は, vforkが呼び出されたポイントで行われます。



exec関数では, LIB$SPAWN ルーチンを使用してサブプロセスを生成し,サブプロセス内で子イメージを起動します。この子プロセスは,定義されているすべての論理名やコマンド・ライン・インタプリタ・シンボルなど,親の環境を継承します。

デフォルトでは,子プロセスは親プロセスのデフォルト (作業) ディレクトリも継承します。ただし, decc$set_child_default_dir関数を使用して,子プロセスの実行開始時のデフォルト・ディレクトリを設定できます。 decc$set_child_default_dir関数の詳細については,『HP C ランタイム・ライブラリ・リファレンス・マニュアル (下巻)』の「リファレンス・セクション」を参照してください。

exec関数は論理名 VAXC$EXECMBX を使用して,親と子の間の通信を行います。この論理名は親イメージのコンテキストの内部に存在しなければなりません。

exec関数は次の情報を子に渡します。

  • 親の umaskの値。この値は,新規にファイルを作成するときに,いずれかのアクセスを禁止するかどうかを指定します。 umask関数の詳細については,『HP C ランタイム・ライブラリ・リファレンス・マニュアル (下巻)』「リファレンス・セクション」を参照してください。

  • 各ファイル記述子に割り当てられているファイル名文字列と,各ファイル内での現在の位置。子プロセスはファイルをオープンし, lseekを呼び出して,親と同じ位置にファイルの現在の位置を設定します。ファイルがレコード・ファイルの場合は,レコード内での親の位置とは無関係に,子プロセスの現在の位置はレコード境界に設定されます。ファイル記述子の詳細については, 第 2 章 を参照してください。 lseek関数の詳細については,『HP C ランタイム・ライブラリ・リファレンス・マニュアル (下巻)』「リファレンス・セクション」を参照してください。
    オープンされているファイルのすべての記述子,ヌル記述子,重複記述子も含めて,親が認識するすべての記述子に関して,この情報が子に送信されます。
    ファイル・ポインタは子に転送されません。親でファイル・ポインタによってオープンされたファイルの場合,対応するファイル記述子だけが子に渡されます。子プロセスが各ファイルのポインタにアクセスする場合は, fdopen関数を呼び出してファイル・ポインタをファイル記述子に関連付ける必要があります。 fdopen関数の詳細については,『HP C ランタイム・ライブラリ・リファレンス・マニュアル (下巻)』「リファレンス・セクション」を参照してください。
    DECC$EXEC_FILEATTR_INHERITANCE 機能論理名を使用すると,子プロセスがファイル位置を継承するかどうかと,継承する場合はどのアクセス・モードについて継承するかを制御できます。 DECC$EXEC_FILEATTR_INHERITANCE の詳細は, 第 1.5 節 を参照してください。

  • シグナル・データベース。SIG_IGN (無視) 動作だけが継承されます。親のシグナル処理ルーチンに子からアクセスすることはできないため,ルーチンとして指定された動作は SIG_DFL (デフォルト) に変更されます。

  • 環境および引数ベクタ。

すべての情報が子に転送されると, execの処理は終了します。親プロセス内の制御は, vforkによって保存されたアドレスに返され,子のプロセス ID は親に返されます。

シグナル動作および SIGCHLD シグナルの詳細については, 第 4.2.4 項 を参照してください。

5.2.2 exec のエラー条件

LIB$SPAWN がサブプロセスを生成できない場合は, exec関数は異常終了します。エラーの原因となる可能性のある条件としては,サブプロセス・クォータの超過や,親と子の間でコンテキスト・メールボックスによる通信が不能であることの検出などがあります。一部のクォータは,超過しても LIB$SPAWN がエラーになることはありませんが, LIB$SPAWN が待ち状態になり,その結果,親プロセスがハングする可能性があります。このようなクォータの例としては,オープン・ファイル・リミット・クォータがあります。

オープン・ファイル・リミット・クォータは少なくとも 20 ファイルに設定する必要があり,平均値はプログラムで同時に実行するプロセスの数の 3 倍です。一度に複数のオープン・パイプを使用する場合や,一度に複数のファイルに対して I/O を実行する場合は,このクォータをさらに大きくする必要があります。このクォータを増大する必要があるかどうかについては,システム管理者にお問い合わせください。

exec関数が異常終了した場合, - 1 という値が返されます。このような障害が発生した後,親は exit関数または _exit関数を呼び出すことが期待されます。どちらの関数も親の vfork呼び出しに戻り,この関数呼び出しは子のプロセス ID を返します。この場合, exec関数から返される子プロセス ID は 0 より小さくなります。 exit関数の詳細については,『HP C ランタイム・ライブラリ・リファレンス・マニュアル (下巻)』「リファレンス・セクション」を参照してください。

5.3 プロセスの同期化

親プロセスが終了すると,子プロセスも終了します。したがって,親プロセスは終了する前に,子プロセスの状態を確認する必要があります。この処理は, HP C RTL 関数 waitを使用して行います。

5.4 プロセス間通信

親プロセスと子プロセスが通信するチャネルはパイプと呼ばれます。パイプを作成するには, pipe関数を使用します。

5.5 プログラムの例

例 5-1 は,子プロセスでイメージを実行するための基本手順を示しています。 例 5-1 の子プロセスはメッセージを 10 回プリントします。

例 5-1 子プロセスの生成
/*      chap_5_exec_image.c     */ 
 
/* This example creates the child process.  The only    */ 
/* functionality given to the child is the ability to   */ 
/* print a message 10 times.                            */ 
 
#include <climsgdef.h>  /* CLI status values  */ 
#include <stdio.h> 
#include <perror.h> 
#include <processes.h> 
#include <stdlib.h> 
 
static const char *child_name = "chap_5_exec_image_child.exe" ; 
 
main() 
{ 
   int status, 
       cstatus; 
 
   /* NOTE:                                            */ 
   /*    Any local automatic variables, even those     */ 
   /*    having the volatile attribute, may have       */ 
   /*    indeterminant values if they are modified     */ 
   /*    between the vfork() call and the matching     */ 
   /*    exec() call.                                  */ 
 
(1)   if ((status = vfork()) != 0) {   
       /* This is either an error or                   */ 
       /* the "second" vfork return, taking us "back"  */ 
       /* to parent mode.                              */ 
(3)       if (status < 0)   
            printf("Parent - Child process failed\n"); 
       else { 
            printf("Parent - Waiting for Child\n"); 
(4)            if ((status = wait(&cstatus)) == -1)  
               perror("Parent - Wait failed"); 
(5)            else if (cstatus == CLI$_IMAGEFNF)    
               printf("Parent - Child does not exist\n"); 
            else 
               printf("Parent - Child final status: %d\n", cstatus); 
        } 
    } 
(2)    else {  /* The FIRST Vfork return is zero, do the exec */ 
           printf("Parent - Starting Child\n"); 
           if ((status = execl(child_name, 0)) == -1) { 
               perror("Parent - Execl failed"); 
               exit(EXIT_FAILURE); 
         } 
    } 
} 
 
---------------------------------------------------------- 

/*      CHAP_5_EXEC_IMAGE_CHILD.C                    */ 
 
/* This is the child program that writes a message   */ 
/* through the parent to "stdout"                    */ 
 
#include <stdio.h> 
 
main() 
{ 
    int i; 
 
    for (i = 0; i < 10; i++) 
        printf("Child - executing\n"); 
    return (255) ;    /* Set an unusual success stat */ 
} 

例 5-1 の補足説明:


目次 索引

© 2012 Hewlett-Packard Development Company, L.P.