mq_notify -
メッセージ到着時に通知を行うよう登録する
#include <mqueue.h>
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
-lrt でリンクする。
mq_notify()
を使うと、メッセージキューディスクリプター
mqdes
で参照される空のメッセージキューに新しくメッセージが到着した時に
非同期の通知 (notification)
の配送が行われるように登録したり、
その解除を行ったりできる。
sevp 引数は
sigevent
構造体へのポインターである。
この構造体の定義と一般的な詳細については
sigevent(7) を参照。
sevp が NULL
でないポインターであれば、
mq_notify()
はメッセージ通知を受け取るように呼び出し元のプロセスを登録する。
sevp が指す
sigevent
構造体の
sigev_notify
フィールドは、どのような通知を行うのかを指定する。
このフィールドは以下の値のいずれかを持つ。
- SIGEV_NONE
- 「空の
(null)」の通知:
呼び出し元のプロセスを通知の宛先として登録するが、
実際にはメッセージが到着した時に通知は送られない。
- SIGEV_SIGNAL
-
sigev_signo
で指定されたシグナルを送って、プロセスに通知する。
一般的な詳細については
sigevent(7) を参照。 siginfo_t
構造体の si_code
フィールドには SI_MESGQ
が設定される。
さらに、 si_pid
にはメッセージを送信したプロセスの
PID が、 si_uid
には送信プロセスの実ユーザー
ID が設定される。
- SIGEV_THREAD
- メッセージの配送時には、
sigev_notify_function
があたかも新しいスレッドの開始関数であるかのように起動される。
詳細は sigevent(7)
を参照。
一つのメッセージキューから通知を受信するように登録できるプロセスは
一つだけである。
sevp が NULL
で、かつ呼び出し元のプロセスがこのメッセージキューからの
通知を受信するに現在登録している場合、登録を削除する。
これ以降、別のプロセスがこのメッセージキューから通知を受信するように
登録できるようになる。
メッセージ通知は、それまで空のキューに新しいメッセージが到着した
場合にのみ行われる。
mq_notify()
が呼び出された時にそのキューが空でない場合、
そのキューが空になり、その後新しいメッセージが到着した時に
初めて通知が行われることになる。
別のプロセスやスレッドが
mq_receive(3)
を使って、空のキューからメッセージの読み出しを待っている場合、
メッセージ通知の登録は全て無視される。
メッセージは
mq_receive(3)
を呼び出しているプロセスやスレッドに配送され、
メッセージ通知の登録は効力を持ったままとなる。
通知は一度だけ行われる。通知が送られた後は、通知要求の登録は削除され、
別のプロセスがメッセージ通知を受信するように登録できるようになる。
通知を受けたプロセスが次の通知も受信したい場合は、
mq_notify()
を使ってその後の通知も受けるように要求することができる。
mq_notify()
を再度呼び出すのは、読み出していないメッセージを全部読み出して
キューが空になる前にすべきである
(キューからのメッセージ読み出しをキューが空になった時に
停止 (block)
せずに行うには、キューを非停止モード
(non-blocking mode)
に設定しておくとよい)。
成功すると、
mq_notify() は 0
を返す。エラーの場合、-1
を返し、
errno
をエラーを示す値に設定する。
- EBADF
-
mqdes
に指定されたメッセージキュー記述子が不正である。
- EBUSY
- 別のプロセスがすでに
このメッセージキューに対する通知を受信するように登録している。
- EINVAL
-
sevp->sigev_notify
が許可された値のいずれでもない。もしくは
sevp->sigev_notify が SIGEV_SIGNAL だが
sevp->sigev_signo
が有効なシグナル番号ではない。
- ENOMEM
- 十分なメモリーがない。
POSIX.1-2008 では、
sevp が NULL
で、呼び出し元のプロセスがキュー
mqdes
に関する通知を受信するように登録されていない場合、エラー
EINVAL
を生成するような実装を行っても「よい」ことになっている。
この節で使用されている用語の説明については、
attributes(7) を参照。
インターフェース |
属性 |
値 |
mq_notify() |
Thread safety |
MT-Safe |
POSIX.1-2001.
In the glibc implementation, the
mq_notify() library function is
implemented on top of the system call of the same name. When
sevp is
NULL, or specifies a notification mechanism other than
SIGEV_THREAD,
the library function directly invokes the system call. For
SIGEV_THREAD, much of the implementation resides within the library,
rather than the kernel. (This is necessarily so, since the thread involved in
handling the notification is one that must be managed by the C library POSIX
threads implementation.) The implementation involves the use of a raw
netlink(7) socket and creates a new thread for each notification that
is delivered to the process.
以下のプログラムは、
コマンドライン引数で指定された名前のメッセージキューへの
通知要求を登録し、通知はスレッドの作成によって行われる。
そのスレッドは、そのキューからメッセージを一つ読み出してから、
プロセスを終了する関数を実行する。
#include <pthread.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void /* スレッド開始関数 */
tfunc(union sigval sv)
{
struct mq_attr attr;
ssize_t nr;
void *buf;
mqd_t mqdes = *((mqd_t *) sv.sival_ptr);
/* 最大メッセージサイズを決定し、
メッセージ受信用のバッファーを確保する */
if (mq_getattr(mqdes, &attr) == -1)
handle_error("mq_getattr");
buf = malloc(attr.mq_msgsize);
if (buf == NULL)
handle_error("malloc");
nr = mq_receive(mqdes, buf, attr.mq_msgsize, NULL);
if (nr == -1)
handle_error("mq_receive");
printf("Read %zd bytes from MQ\n", nr);
free(buf);
exit(EXIT_SUCCESS); /* プロセスを終了する */
}
int
main(int argc, char *argv[])
{
mqd_t mqdes;
struct sigevent sev;
if (argc != 2) {
fprintf(stderr, "Usage: %s <mq-name>\n", argv[0]);
exit(EXIT_FAILURE);
}
mqdes = mq_open(argv[1], O_RDONLY);
if (mqdes == (mqd_t) -1)
handle_error("mq_open");
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = tfunc;
sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_ptr = &mqdes; /* スレッド関数に渡す引数 */
if (mq_notify(mqdes, &sev) == -1)
handle_error("mq_notify");
pause(); /* プロセスはスレッド関数により終了される */
}
mq_close(3),
mq_getattr(3),
mq_open(3),
mq_receive(3),
mq_send(3),
mq_unlink(3),
mq_overview(7),
sigevent(7)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。