C言語 - 標準ライブラリ - プロセス・スレッド共有リソース - POSIX メッセージキュー

クラウディア 
1. 概要
2. mq_open オープン
3. mq_send 送信
4. mq_receive 受信
5. mq_unlink 削除

1. 概要

 「mqueue.h」で、「POSIX」系のメッセージキューの操作を行う関数を定義しています。  以下の関数は、「IEEE Std 1003.1-2004 (“POSIX.1”) 」に準拠しています。

2. mq_open オープン


#include <mqueue.h>

mqd_t mq_open(const char *name, int oflag, ...);
 「mq_open()」は、プロセスとメッセージ キュー間の接続をメッセージ キュー記述子で確立します。  メッセージ キューを参照するオープン メッセージ キュー記述子と、そのオープン メッセージ キュー記述子を参照するメッセージ キュー記述子を作成します。  メッセージ キュー記述子は、他の関数がそのメッセージ キューを参照するために使用されます。  「name」は、メッセージ キューの名前を示す文字列を指します。  「name」は、パス名の構築規則に従う必要があります。  「name」はスラッシュ文字で始まる必要があります。  同じ「name」値で「mq_open()」を呼び出すプロセスは、その名前が削除されていない限り、同じメッセージ キュー オブジェクトを参照します。  「name」が既存のメッセージ キューの名前ではなく、作成が要求されていない場合、「mq_open()」は失敗し、エラーを返します。  「oflag」は、メッセージ キューへの必要な受信および、または送信アクセスを要求します。  メッセージの受信またはメッセージの送信に対する要求されたアクセス許可は、呼び出しプロセスに、同等に保護されたファイルへの読み取りまたは書き込みアクセスがそれぞれ許可されている場合に許可されます。  「oflag」の値は、次のリストの値のビット単位の包含「OR」です。  アプリケーションは、「oflag」の値に、次の最初の 3 つの値 (アクセス モード) の 1 つだけを指定する必要があります。 ・O_RDONLY メッセージの受信用にメッセージ キューを開きます プロセスは、返されたメッセージ キュー記述子を「mq_receive()」で使用できますが、「mq_send()」では使用できません メッセージ キューは、同じプロセスまたは異なるプロセスで、メッセージの受信用に複数回開くことができます ・O_WRONLY キューを開いてメッセージを送信します プロセスは、返されたメッセージ キュー記述子を「mq_send()」で使用できますが、「mq_receive()」では使用できません メッセージ キューは、同じプロセスまたは異なるプロセスで、メッセージを送信するために複数回開くことができます ・O_RDWR キューを開いてメッセージの受信と送信の両方を行います プロセスは、「O_RDONLY」および「O_WRONLY」で許可されている関数のいずれかを使用できます メッセージ キューは、同じプロセスまたは異なるプロセスで、メッセージを送信するために複数回開くことができます  残りのフラグの任意の組み合わせを「oflag」の値に指定できます。 ・O_CREAT メッセージ キューを作成します これには、「mode (mode_t 型) 」と「attr (mq_attr 構造体へのポインタ) 」という 2 つの追加引数が必要です パス名「name」が、まだ存在するメッセージ キューを作成するために既に使用されている場合、 このフラグは、「O_EXCL」で説明されている場合を除き、効果がありません それ以外の場合は、メッセージ キューはメッセージなしで作成されます メッセージ キューのユーザー「ID」は、プロセスの有効なユーザー「ID」に設定され、 メッセージ キューのグループ「ID」は、プロセスの有効なグループ ID に設定されます メッセージ キューの許可ビットは、プロセスのファイル モード作成マスクで設定されたものを除き、 モード引数の値に設定されます ファイル許可ビット以外のモードのビットが指定された場合、その効果は未指定です 「attr」が「NULL」の場合、メッセージ キューは実装定義のデフォルトのメッセージ キュー属性で作成されます 「attr」が「NULL」以外で、呼び出しプロセスが「name」に対して適切な権限を持っている場合、 メッセージ キューの「mq_maxmsg」属性と「mq_msgsize」属性は、「attr」によって参照される 「mq_attr」構造体の対応するメンバーの値に設定されます 「attr」が「NULL」以外で、呼び出しプロセスが「name」に対して適切な権限を持っていない場合、 「mq_open()」は失敗し、メッセージ キューを作成せずにエラーを返します ・O_EXCL 「O_EXCL」と「O_CREAT」が設定されている場合、メッセージ キュー名が存在すると「mq_open()」は失敗します。 ・O_NONBLOCK 「mq_send()」または「mq_receive()」が現在利用できないリソースまたはメッセージを待機するか、 または「errno」を「EAGAIN」に設定して失敗するかを決定します 詳細については、「mq_send() 」および「mq_receive()」 を参照してください  「mq_open()」は、キューにメッセージを追加または削除しません。  注記  「FreeBSD」は、ファイル記述子に基づいてメッセージ キューを実装します。  記述子は「fork()」の後に子に継承されます。  記述子は「exec()」の後に新しいイメージで閉じられます。  「select()」および「kevent()」は、メッセージ キュー記述子に対してサポートされています。  モジュールのロードまたはサービスのカーネルへのコンパイルの手順については、「mqueuefs()」のマニュアル ページを参照してください。  正常に完了すると、関数はメッセージ キュー記述子を返します。  それ以外の場合は、関数は「(mqd_t)-1」を返し、「errno」を設定します。  「mq_open()」は、次の場合に失敗します: ・EACCES メッセージ キューが存在し、「oflag」で指定された権限が拒否されているか、メッセージ キューが存在せず、 メッセージ キューを作成する権限が拒否されています ・EEXIST 「O_CREAT」および「O_EXCL」が設定されており、指定されたメッセージ キューがすでに存在します ・EINTR 「mq_open()」がシグナルによって割り込まれました ・EINVAL 指定された名前では「mq_open()」はサポートされていません ・EINVAL 「oflag」に「O_CREAT」が指定され、「attr」の値が「NULL」ではなく、 「mq_maxmsg」または「mq_msgsize」のいずれかが 0 以下でした ・EMFILE このプロセスで現在使用されているメッセージ キュー記述子またはファイル記述子が多すぎます ・ENAMETOOLONG 名前引数の長さが「PATH_MAX」を超えているか、パス名コンポーネントが「NAME_MAX」より長くなっています ・ENFILE システムで現在開いているメッセージ キューが多すぎます ・ENOENT 「O_CREAT」が設定されておらず、指定されたメッセージ キューが存在しません ・ENOSPC 新しいメッセージ キューを作成するためのスペースが不足しています  「FreeBSD」の実装では、「name」の値に厳しい要件が課されます。  「name」は、スラッシュ (‘/’) で始まり、他のスラッシュ文字を含んではなりません。  「mode」および「attr」引数は可変長であるため、通常とは異なる呼び出し規約になる可能性があります。

3. mq_send 送信


#include <mqueue.h>

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio, const struct timespec *abs_timeout);
 「mq_send()」は、引数「msg_ptr」が指すメッセージを「mqdes」で指定されたメッセージキューに追加します。  「msg_len」引数は、「msg_ptr」が指すメッセージの長さをバイト単位で指定します。  「msg_len」の値は、メッセージキューの「mq_msgsize」属性以下である必要があります。そうでない場合、「mq_send()」は失敗します。  指定されたメッセージキューがいっぱいでない場合、「mq_send()」は、メッセージがメッセージキューの「msg_prio」引数で指定された位置に挿入されたかのように動作します。  「msg_prio」の数値が大きいメッセージは、「msg_prio」の値が小さいメッセージの前に挿入されます。  キュー内に「msg_prio」が等しい他のメッセージがある場合は、そのメッセージの後にメッセージが挿入されます。  「msg_prio」の値は、「MQ_PRIO_MAX」未満である必要があります。  指定されたメッセージ キューがいっぱいで、「mqdes」に関連付けられたメッセージキュー記述で「O_NONBLOCK」が設定されていない場合、「mq_send()」は、メッセージをキューに入れるためのスペースが利用可能になるまで、または「 mq_send()」がシグナルによって割り込まれるまでブロックします。  メッセージ キューにスペースが利用可能になり、優先度スケジューリング オプションがサポートされているときに複数のスレッドが送信を待機している場合、最も長く待機していた最も優先度の高いスレッドが、メッセージを送信するためにブロック解除されます。  それ以外の場合、どの待機スレッドがブロック解除されるかは指定されていません。  指定されたメッセージ キューがいっぱいで、「mqdes」に関連付けられたメッセージ キュー記述で O_NONBLOCK が設定されている場合、メッセージはキューに入れられず、「mq_send()」はエラーを返します。  「mq_timedsend()は、「mq_send()」に定義された方法で、「mqdes」によって指定されたメッセージキューにメッセージを追加します。  ただし、指定されたメッセージ キューがいっぱいで、「mqdes」に関連付けられたメッセージキュー記述で「O_NONBLOCK」が設定されていない場合、指定されたタイムアウトが経過すると、キューに十分な空きができるまでの待機は終了します。  メッセージ キュー記述で「O_NONBLOCK」が設定されている場合、「mq_timedsend()」は「mq_send()」と同等です。  タイムアウトは、タイムアウトの基準となるクロックで測定された「abs_timeout」で指定された絶対時間が経過したとき (つまり、そのクロックの値が「abs_timeout」と等しいかそれを超えたとき)、または呼び出し時に「abs_timeout」で指定された絶対時間がすでに経過していたときに、期限切れになります。  タイムアウトは「CLOCK_REALTIME」クロックに基づいています。  正常に完了すると、「mq_send()」および「mq_timedsend()」は値 0 を返します。  それ以外の場合、メッセージはキューに登録されず、-1 を返し、「errno」が設定されます。  「mq_send()」および「mq_timedsend()」システム コールは、次の場合に失敗します。 ・EAGAIN 「mqdes」に関連付けられたメッセージキュー記述子に「O_NONBLOCK」フラグが設定されており、 指定されたメッセージキューがいっぱいです ・EBADF 「mqdes」引数は、書き込み用に開かれた有効なメッセージ キュー記述子ではありません ・EINTR シグナルによって「mq_send()」または「mq_timedsend()」の呼び出しが中断されました ・EINVAL 「msg_prio」の値が有効な範囲外でした ・EINVAL プロセスまたはスレッドがブロックされ、 「abs_timeout」パラメータに 0 未満または 10 億以上のナノ秒フィールド値が指定されました ・EMSGSIZE 指定されたメッセージの長さ「msg_len」は、メッセージキューのメッセージ サイズ属性を超えています。 ・ETIMEDOUT メッセージキューが開かれたときに「O_NONBLOCK」フラグが設定されていませんでしたが、 メッセージがキューに追加される前にタイムアウトが経過しました。

4. mq_receive 受信


#include <mqueue.h>

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout);
 「mq_receive()」は、「mqdes」で指定された、メッセージキューから、最も優先度の高いメッセージのうち最も古いメッセージを受信します。  「msg_len」引数で指定されたバッファのサイズ (バイト単位) がメッセージキューの「mq_msgsize」属性より小さい場合、失敗し、エラーを返します。  それ以外の場合、選択されたメッセージはキューから削除され、「msg_ptr」引数で指定されたバッファにコピーされます。  「msg_prio」が「NULL」でない場合、選択されたメッセージの優先度は「msg_prio」で参照される場所に格納されます。  指定されたメッセージキューが空で、「mqdes」に関連付けられたメッセージキュー記述で「O_NONBLOCK」が設定されていない場合、「mq_receive()」は、メッセージがメッセージキューにエンキューされるか、「mq_receive()」がシグナルによって中断されるまでブロックします。  メッセージが空のキューに到着したときに複数のスレッドがメッセージの受信を待機しており、優先度スケジューリング オプションがサポートされている場合は、最も長く待機していた最も優先度の高いスレッドがメッセージの受信に選択されます。  それ以外の場合は、どの待機スレッドがメッセージを受信するかは指定されていません。  指定されたメッセージ キューが空で、「mqdes」に関連付けられたメッセージ キュー記述で 「O_NONBLOCK」が設定されている場合、キューからメッセージは削除されず、「mq_receive()」はエラーを返します。  「mq_timedreceive()」は、「mq_receive()」で説明されているように、「mqdes」で指定されたメッセージキューから最も優先度の高いメッセージのうち最も古いメッセージを受信します。  ただし、メッセージキューが「mq_open()」よって開かれたときに「O_NONBLOCK」が指定されておらず、受信を満たすメッセージがキューに存在しない場合は、指定されたタイムアウトが経過すると、そのようなメッセージの待機は終了します。  「O_NONBLOCK」が設定されている場合、このシステム コールは「mq_receive()」と同等です。  タイムアウトは、タイムアウトの基準となるクロックで測定された「abs_timeout」で指定された絶対時間が経過すると (つまり、そのクロックの値が「abs_timeout」と等しいかそれを超えると)、または呼び出し時に「abs_timeout」で指定された絶対時間がすでに経過している場合に期限切れになります。  タイムアウトは「CLOCK_REALTIME」クロックに基づきます。  正常に完了すると、「mq_receive()」および「mq_timedreceive()」システム コールは、選択されたメッセージの長さをバイト単位で返し、メッセージをキューから削除します。  それ以外の場合、メッセージはキューから削除されず、システム コールは値 -1 を返し、「errno」が設定されます。  「mq_receive()」および「mq_timedreceive()」は、次の場合に失敗します: ・EAGAIN 「mqdes」に関連付けられたメッセージキュー記述子に「O_NONBLOCK」フラグが設定されており、 指定されたメッセージ キューが空です ・EBADF 「mqdes」引数は、読み取り用に開かれた有効なメッセージ キュー記述子ではありません ・EMSGSIZE 指定されたメッセージ バッファサイズ「msg_len」は、メッセージキューのメッセージサイズ属性よりも小さいです ・EINTR 「mq_receive()」または「mq_timedreceive()」操作がシグナルによって中断されました。 ・EINVAL プロセスまたはスレッドがブロックされ、 「abs_timeout」パラメータに 0 未満または 10 億以上のナノ秒フィールド値が指定されました ・ETIMEDOUT メッセージ キューが開かれたときに「O_NONBLOCK」フラグが設定されていませんでしたが、 指定されたタイムアウトが経過する前にキューにメッセージが到着しませんでした

5. mq_unlink 削除


#include <mqueue.h>

int mq_unlink(const char *name);
 「mq_unlink()」は、文字列 name で指定されたメッセージ キューを削除します。  「mq_unlink()」が呼び出されたときに 1 つ以上のプロセスがメッセージ キューを開いている場合、メッセージ キューの破棄は、メッセージ キューへのすべての参照が閉じられるまで延期されます。  ただし、「mq_unlink()」呼び出しは、すべての参照が閉じられるまでブロックする必要はなく、すぐに戻ることができます。  「mq_unlink()」の呼び出しが成功した後、名前を再利用すると、その後「mq_open()」はこの名前のメッセージ キューが存在しないかのように動作します。  正常に完了すると、値 0 が返されます。  それ以外の場合は、値 -1 が返され、「errno」が設定されます。  mq_unlink()」は、次の場合に失敗します。 ・EACCESS 「name」で表されるメッセージ キューのリンクを解除する権限が拒否されました。 ・EINVAL 「name」が無効です。 ・ENAMETOOLONG 「name」引数の長さが「PATH_MAX」を超えているか、パス名コンポーネントが「NAME_MAX」より長いです。 ・ENOENT メッセージ キューが存在しません。 ・ENOSYS 「mqueuefs()」モジュールがロードされておらず、カーネルに組み込んでいません。
AbemaTV 無料体験
薬屋の独り言
JETBOY
損保との違い
それがだいじWi-Fi