One of the problems with System V message queues is that it is not possible to tell a process when a message has been placed in a queue. Polling is a waste of CPU time.
Posix message queues allow asynchronous event notifications to tell when a message is placed in an empty message queue.
There are two ways to do this: when a message is placed in an empty queue, either a signal is generated to notify it, or a thread is created to execute a specific program to do what the message should do when it arrives.
This notification is done by calling mq_notify establishment
#include <mqueue.h> int mq_notify(mqd_t mqdes, const struct sigevent* notification);
This function establishes or deletes asynchronous event notifications for a specified queue
(1). If the notification parameter is not null, the current process expects to be notified when a message arrives at the previously empty column specified.
(2). If the notification parameter is empty and the current process is registered to receive notifications for the specified queue, the existing registration will be revoked.
The structure of struct sigevent is:
union sigval {} /* Passed parameter */
(int) sival_int; * Parameters passed by the /* signaling mechanism*/
* void *sival_ptr; /* If parameter passed by threading mechanism*/
};
struct sigevent {
(int) sigev_notify; /* Set notification mechanism method with thread SIGEV_THREAD, SIGEV_SIGNAL SIGNAL*/
(int) sigev_signo; /* If signal mechanism, this parameter is set to triggered signal*/
union sigval sigev_value;/* Parameters passed*/
void (*sigev_notify_function)(union sigval); /* If threading mechanism, this parameter is threading function*/
* void *sigev_notify_attributes; /* Thread Function Properties*/
};
A few points to note:
1. Only one thread function needs to be registered.
2. Message mechanism triggers when the message queue is empty and when the message queue is not empty, data arrival does not trigger.
3. When a message mechanism triggers, it needs to be re-registered, and in our applications, when a thread function triggers, it needs to be re-registered. You can see it in the code that follows.
2. Simple examples
#include #include #include #include #include #include #include #include const char *mq_name = "/mq_test"; inline void handle_error(const char *msg) { perror(msg); exit(EXIT_FAILURE); } 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() error\n"); } buf = malloc(attr.mq_msgsize); if (buf == nullptr) { handle_error("malloc() error\n"); } nr = mq_receive(mqdes, (char *) buf, attr.mq_msgsize, nullptr); if (nr == -1) { handle_error("mq_receive() error\n"); } printf("Read %zd bytes from MQ\n", nr); free(buf); exit(EXIT_SUCCESS); } int main() { mqd_t mqdes = mq_open(mq_name, O_CREAT | O_RDWR, 0777, nullptr); if (mqdes < (mqd_t) 0) { handle_error("mq_open() error\n"); } struct sigevent sev; bzero(&sev, sizeof(sev)); sev.sigev_notify = SIGEV_THREAD; sev.sigev_notify_function = tfunc; sev.sigev_notify_attributes = nullptr; sev.sigev_value.sival_ptr = &mqdes; // Parameters passed to tfunc if (mq_notify(mqdes, &sev) == -1) { handle_error("mq_notify() error\n"); } puts("sleep for 2 second..."); sleep(2); const char *msg = "hello world!"; mq_send(mqdes, msg, strlen(msg), 1); pause(); exit(EXIT_SUCCESS); }