mq_notify(3) メッセージ到着時に通知を行うよう登録する

書式

#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_notifySIGEV_SIGNAL だが sevp->sigev_signo が有効なシグナル番号ではない。
ENOMEM
十分なメモリがない。

POSIX.1-2008 では、 sevp が NULL で、呼び出し元のプロセスがキュー mqdes に関する通知を受信するように登録されていない場合、エラー EINVAL を生成するような実装を行っても「よい」ことになっている。

準拠

POSIX.1-2001.

以下のプログラムは、 コマンドライン引き数で指定された名前のメッセージキューへの 通知要求を登録し、通知はスレッドの作成によって行われる。 そのスレッドは、そのキューからメッセージを一つ読み出してから、 プロセスを終了する関数を実行する。

プログラムのソース

#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();    /* プロセスはスレッド関数により終了される */
}

この文書について

この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。