Inter-process-communication-message-queues
メッセージキュー
共有メモリが既にあるのに、なぜメッセージキューが必要なのですか? それは複数の理由によるものです、単純化のためにこれを複数のポイントに分割してみましょう-
- 理解されているように、メッセージがプロセスによって受信されると、他のプロセスで使用できなくなります。 一方、共有メモリでは、データは複数のプロセスがアクセスできます。
- 小さなメッセージ形式で通信したい場合。
- 複数のプロセスが同時に通信する場合は、共有メモリデータを同期で保護する必要があります。
- 共有メモリを使用した書き込みおよび読み取りの頻度が高い場合、機能の実装は非常に複雑になります。 この種のケースでの使用に関しては価値がありません。
- すべてのプロセスが共有メモリにアクセスする必要はないが、それだけを必要とするプロセスが非常に少ない場合は、メッセージキューを使用して実装する方が良いでしょう。
- 異なるデータパケットと通信する場合、プロセスAがメッセージタイプ1をプロセスBに、メッセージタイプ10をプロセスCに、メッセージタイプ20をプロセスDに送信するとします。 この場合、メッセージキューを使用して実装する方が簡単です。 指定されたメッセージタイプを1、10、20として単純化するには、以下で説明するように、0または+ veまたは-veのいずれかです。
- もちろん、メッセージキューの順序はFIFO(先入れ先出し)です。 キューに挿入される最初のメッセージは、取得される最初のメッセージです。
共有メモリまたはメッセージキューを使用するかどうかは、アプリケーションの必要性と、それをどの程度効果的に利用できるかによって異なります。
メッセージキューを使用した通信は、次の方法で発生する可能性があります-
- あるプロセスによる共有メモリへの書き込みと、別のプロセスによる共有メモリからの読み取り。 認識しているように、読み取りは複数のプロセスでも実行できます。
- 異なるデータパケットを使用した1つのプロセスによる共有メモリへの書き込みと、複数のプロセスによる、つまりメッセージタイプごとの共有メモリからの読み取り。
メッセージキューに関する特定の情報を見たので、今度はメッセージキューをサポートするシステムコール(System V)を確認します。
メッセージキューを使用して通信を実行するには、次の手順があります-
- ステップ1 *-メッセージキューを作成するか、既存のメッセージキューに接続する(msgget())
- ステップ2 *-メッセージキューに書き込む(msgsnd())
- ステップ3 *-メッセージキューからの読み取り(msgrcv())
- ステップ4 *-メッセージキューで制御操作を実行する(msgctl())
次に、上記の呼び出しの構文と特定の情報を確認しましょう。
このシステムコールは、System Vメッセージキューを作成または割り当てます。 次の引数を渡す必要があります-
- 最初の引数keyは、メッセージキューを認識します。 キーは、任意の値でも、ライブラリ関数ftok()から派生した値でもかまいません。
- 2番目の引数shmflgは、IPC_CREAT(存在しない場合はメッセージキューを作成する)またはIPC_EXCL(IPC_CREATとともに使用してメッセージキューを作成し、メッセージキューが既に存在する場合は呼び出しが失敗する)などの必要なメッセージキューフラグを指定します。 許可も渡す必要があります。
注-権限の詳細については、前のセクションを参照してください。
この呼び出しは、成功した場合は有効なメッセージキュー識別子(メッセージキューの以降の呼び出しに使用)を返し、失敗した場合は-1を返します。 失敗の原因を知るには、errno変数またはperror()関数で確認してください。
この呼び出しに関するさまざまなエラーは、EACCESS(許可が拒否されました)、EEXIST(既に存在するキューは作成できません)、ENOENT(キューが存在しません)、ENOMEM(キューを作成するのに十分なメモリがありません)などです。
このシステムコールは、メッセージをメッセージキューに送信/追加します(システムV)。 次の引数を渡す必要があります-
- 最初の引数msgidは、メッセージキュー、つまりメッセージキュー識別子を認識します。 msgget()の成功時に識別子の値を受け取ります
- 2番目の引数、msgpは、次の形式の構造で定義された、呼び出し元に送信されるメッセージへのポインタです-
変数mtypeは、さまざまなメッセージタイプとの通信に使用されます。詳細については、msgrcv()呼び出しで説明しています。 変数mtextは、msgsz(正の値)でサイズが指定された配列またはその他の構造です。 mtextフィールドが言及されていない場合、それは許可されているゼロサイズのメッセージと見なされます。
- 3番目の引数msgszは、メッセージのサイズです(メッセージはヌル文字で終了する必要があります) *4番目の引数msgflgは、IPC_NOWAITなどの特定のフラグを示します(キューにメッセージが見つからない場合はすぐに戻ります。MSG_NOERROR(msgszバイトを超える場合はメッセージテキストを切り捨てます)
この呼び出しは、成功すると0を返し、失敗すると-1を返します。 失敗の原因を知るには、errno変数またはperror()関数で確認してください。
このシステムコールは、メッセージキュー(システムV)からメッセージを取得します。 次の引数を渡す必要があります-
- 最初の引数msgidは、メッセージキュー、つまりメッセージキュー識別子を認識します。 msgget()の成功時に識別子の値を受け取ります
- 2番目の引数msgpは、呼び出し元から受信したメッセージのポインターです。 それは、次の形式の構造で定義されています-
変数mtypeは、異なるメッセージタイプとの通信に使用されます。 変数mtextは、msgsz(正の値)でサイズが指定された配列またはその他の構造です。 mtextフィールドが言及されていない場合、それは許可されているゼロサイズのメッセージと見なされます。
- 3番目の引数msgszは、受信したメッセージのサイズです(メッセージはヌル文字で終了する必要があります)
- fouth引数、msgtypeは、メッセージのタイプを示しています-
- * msgtypeが0の場合-キュー内の最初の受信メッセージを読み取ります
- msgtypeが+ ve の場合-タイプmsgtypeのキュー内の最初のメッセージを読み取ります(msgtypeが10の場合、他のタイプが最初にキューにある場合でもタイプ10の最初のメッセージのみを読み取ります)
- msgtypeが-ve の場合-メッセージタイプの絶対値以下の最低タイプの最初のメッセージを読み取ります(たとえば、msgtypeが-5の場合、5より小さいタイプの最初のメッセージを読み取ります。つまり、メッセージタイプは1から5) *5番目の引数msgflgは、IPC_NOWAITなどの特定のフラグを示します(キューにメッセージが見つからない場合はすぐに戻ります。MSG_NOERROR(msgszバイトを超える場合はメッセージテキストを切り捨てます)
この呼び出しは、成功するとmtext配列で実際に受信したバイト数を返し、失敗した場合は-1を返します。 失敗の原因を知るには、errno変数またはperror()関数で確認してください。
このシステムコールは、メッセージキュー(システムV)の制御操作を実行します。 次の引数を渡す必要があります-
最初の引数msgidは、メッセージキュー、つまりメッセージキュー識別子を認識します。 msgget()の成功時に識別子の値を受け取ります
2番目の引数cmdは、メッセージキューで必要な制御操作を実行するコマンドです。 cmdの有効な値は-
3番目の引数bufは、struct msqid_dsという名前のメッセージキュー構造体へのポインターです。 この構造の値は、cmdに従ってsetまたはgetに使用されます。
この呼び出しは、渡されたコマンドに応じて値を返します。 IPC_INFOおよびMSG_INFOまたはMSG_STATが成功すると、メッセージキューのインデックスまたは識別子が返されます。他の操作の場合は0、失敗の場合は-1が返されます。 失敗の原因を知るには、errno変数またはperror()関数で確認してください。
メッセージキューに関する基本的な情報とシステムコールを確認したら、今度はプログラムで確認します。
プログラムを見る前に説明を見てみましょう-
- ステップ1 *-2つのプロセスを作成します。1つはメッセージキュー(msgq_send.c)に送信するためのもので、もう1つはメッセージキュー(msgq_recv.c)から取得するためのものです
- ステップ2 *-ftok()関数を使用してキーを作成します。 このため、一意のキーを取得するために、最初にファイルmsgq.txtが作成されます。
- ステップ3 *-送信プロセスは以下を実行します。
- ユーザーから入力された文字列を読み取ります
- 存在する場合、新しい行を削除します
- メッセージキューに送信する
- 入力が終了するまでプロセスを繰り返します(CTRL + D)
- 入力の終了を受信したら、メッセージ「end」を送信してプロセスの終了を通知します
- ステップ4 *-受信プロセスで、以下を実行します。
- キューからメッセージを読み取ります
- 出力を表示します
- 受信したメッセージが「終了」の場合、プロセスを終了して終了します
単純化するために、このサンプルではメッセージタイプを使用していません。 また、1つのプロセスがキューに書き込み、別のプロセスがキューから読み取りを行っています。 これは必要に応じて拡張できます。つまり、理想的には、1つのプロセスがキューに書き込み、複数のプロセスがキューから読み取ります。
次に、プロセス(メッセージをキューに送信)を確認します–ファイル:msgq_send.c
コンパイルおよび実行手順
以下は、メッセージ受信プロセスからのコードです(キューからメッセージを取得)–ファイル:msgq_recv.c