#include <mqueue.h> mqd_t mq_notify(mqd_t mqdes, const struct sigevent *notification);
The notification argument is a pointer to a sigevent structure that is defined something like the following:
union sigval {          /* Data passed with notification */
    int     sival_int;         /* Integer value */
    void   *sival_ptr;         /* Pointer value */
};
struct sigevent {
    int          sigev_notify; /* Notification method */
    int          sigev_signo;  /* Notification signal */
    union sigval sigev_value;  /* Data passed with
                                  notification */
    void       (*sigev_notify_function) (union sigval);
                               /* Function for thread
                                  notification */
    void        *sigev_notify_attributes;
                               /* Thread function attributes */
};
If notification is a non-NULL pointer, then mq_notify() registers the calling process to receive message notification. The sigev_notify field of the sigevent to which notification points specifies how notification is to be performed. This field has one of the following values:
Only one process can be registered to receive notification from a message queue.
If notification is NULL, and the calling process is currently registered to receive notifications for this message queue, then the registration is removed; another process can then register to receive a message notification for this queue.
Message notification only occurs when a new message arrives and the queue was previously empty. If the queue was not empty at the time mq_notify() was called, then a notification will only occur after the queue is emptied and a new message arrives.
If another process or thread is waiting to read a message from an empty queue using mq_receive(3), then any message notification registration is ignored: the message is delivered to the process or thread calling mq_receive(3), and the message notification registration remains in effect.
Notification occurs once: after a notification is delivered, the notification registration is removed, and another process can register for message notification. If the notified process wishes to receive the next notification, it can use mq_notify() to request a further notification. This should be done before emptying all unread messages from the queue. (Placing the queue in non-blocking mode is useful for emptying the queue of messages without blocking once it is empty.)
POSIX.1-2008 says that an implementation may generate an EINVAL error if notification is NULL, and the caller is not currently registered to receive notifications for the queue mqdes.
#include <pthread.h>
#include <mqueue.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void                     /* Thread start function */
tfunc(union sigval sv)
{
    struct mq_attr attr;
    ssize_t nr;
    void *buf;
    mqd_t mqdes = *((mqd_t *) sv.sival_ptr);
    /* Determine max. msg size; allocate buffer to receive msg */
    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 %ld bytes from MQ\n", (long) nr);
    free(buf);
    exit(EXIT_SUCCESS);         /* Terminate the process */
}
int
main(int argc, char *argv[])
{
    mqd_t mqdes;
    struct sigevent not;
    assert(argc == 2);
    mqdes = mq_open(argv[1], O_RDONLY);
    if (mqdes == (mqd_t) -1)
        handle_error("mq_open");
    not.sigev_notify = SIGEV_THREAD;
    not.sigev_notify_function = tfunc;
    not.sigev_notify_attributes = NULL;
    not.sigev_value.sival_ptr = &mqdes;   /* Arg. to thread func. */
    if (mq_notify(mqdes, ¬) == -1)
        handle_error("mq_notify");
    pause();    /* Process will be terminated by thread function */
}