パイプでは残念なことに親子の間でしか通信ができません。ファイル記述子 を共有する必要があるからです。実際には親子関係のないプロセスとの通信が 必要です。そのための方法がメッセージキューと呼ばれるものです。この仕組 みは後から出てくるセマフォと共有メモリーを合わせてIPC(InterProcess Communication)としてSYSTEM Vに導入されましたが現在ではSunOSやULTRIXに も導入されています。
プロセス間で情報交換をする方法にはいくつかありますが、メッセージはそ の中で比較的少ない量のデータを同期的に素早く交換する方法です。プロセス 間で共通のメッセージキーを決めておきます。そのキーを使ってメッセージを 送ったり受け取ったりします。次の例を見てみましょう。
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct msgbuf { long mtype; char mtext[ 512 ]; } msg; msgid = msgget( 12345, IPC_CREAT | 0666 ); if( msgid == -1 ) perror( 0 );/* メッセージIDを得られなかった。*/ ... msg.mtype = 1; strcpy( msg.mtext, "Test message for msgsnd" ); st = msgsnd( msgid, &msg, strlen( msg.mtext ), IPC_NOWAIT ); ... len = msgrcv( msgid, &msg, sizeof( msg.mtext ), 2, 0 );
msggetでメッセージキー12345に対応するメッセージキューを作ります。0でな いキーを使うとパブリックなメッセージキューになります。計算機上の誰から もみえることになります。個人的に使いたい場合はIPC_PRIVATE(実際の値は0) をキーとして使います。次の引数はメッセージキューの選び方を指定します。 IPC_CREATは新規に作成することを表わしますが既に存在する場合はそれを使 います。IPC_EXCLが同時に指定された場合、既に存在しているとエラーになり ます。IPC_ALLOCは既に存在するものを使うことを指示します。存在しなけれ ばエラーです。あわせて指定している0666はアクセスモードを表わします。誰 でも読み書きできる(--rw-rw-rw-)ことを示しています。
メッセージキューはmsgidで識別されます。メッセージタイプ1のメッセージ を用意してmsgsndで送ります。IPC_NOWAITは相手が受け取らなくてもシステム コールがら戻るよう指定したものです。次にmsgrcvでメッセージタイプ2のメッ セージを受け取ろうとします。フラッグが0なのでメッセージを受け取るまで システムコールからは戻ってきません。ここでメッセージタイプ2の替わりに0 を指定するとメッセージキューに入っているメッセージをメッセージタイプに 関係なく取り出してくれます。取り出したメッセージのタイプはmsg. mtype でわかります。
このようにして送り手と受け手のプログラムを作って走らせてみましょう。 受け手をms grcvとします。ここでメッセージキューの状況を見てみます。シェ ルからipcsコマンドを実行します。
% msgrcv & [1] 8473 % ipcs -q IPC status from ganmo as of Tue Apr 5 16:59:51 1994 T ID KEY MODE OWNER GROUP Message Queues: q 50 0x00003039 -Rrw-rw-rw- chikuwa 100
ipcsはプロセス間通信(IPC)の状態を表示するコマンドです。キー12345(16進 だと3039)のメッセージキューが作られ、IDは50が割り当てられています。大 文字Rは現在メッセージが送られるのを待っているプロセスがあることを示し ています。大文字Sが表示されたときはメッセージが受け取られるのを待って いるプロセスがあることを示します。メッセージキューは一度作られると消さ れるまではそれを参照するプロセスがなくとも存在を続けます。msgctlシステ ムコールで消去などの制御を行ないます。シェルレベルからはipcrmコマンド を使ってメッセージキューの除去が出来ます。manで見てください。上の例で はメッセージキューのIDは50ですから次のようになります。
% ipcrm -q 50
メッセージキューの中に何が入っているか調べたいこともあると思います。 msgctlシステムコールを使います。
struct msqid_ds buf; st = msgctl( msgid, IPC_STAT, &buf );
最初の引数はmsggetで取ったIDです。次の引数はそのメッセージキューに対す る操作を表わし、IPC_STATは状態取得を指示します。IPC_SETでパラメータ設 定、IPC_RMIDでメッセージキューの削除を行います。IPC_STATで渡される三番 目の引数の構造体msq_idは次のようなメンバーを持っています。 /usr/include/sys/msg.hに定義されています。
struct msqid_ds { /* operation permission struct */ struct ipc_perm msg_perm; /* ptr to first message on q */ struct msg *msg_first; /* ptr to last message on q */ struct msg *msg_last; ushort msg_cbytes; /* current # bytes on q */ ushort msg_qnum; /* # of messages on q */ ushort msg_qbytes; /* max # of bytes on q */ ushort msg_lspid; /* pid of last msgsnd */ ushort msg_lrpid; /* pid of last msgrcv */ time_t msg_stime; /* last msgsnd time */ time_t msg_rtime; /* last msgrcv time */ time_t msg_ctime; /* last change time */ };
メッセージがあるかどうかはbuf.msg_qnumを見ればわかることになります。