1. Message Queuing
Message queue with the conduit
Same point:
With all kernel space, communicate, if not unlink, even if the process close, Message Queue will continue to exist.
And because by means of the kernel space, there is another data copying between user space and kernel space, and consumption efficiency.
difference:
Similarly SMS message queue, the peer need not online.
Pipeline similar phone, the need for end-line.
2.API
(1)mq_open
mqd_t mq_open(const char *name, int oflag); mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
mq_open() creates a new POSIX message queue or opens an existing queue.
flag must value
O_RDONLY, O_WRONLY, O_RDWR
flag optional value
O_CLOEXEC, O_CREAT, O_EXCL, O_UNBLOCK
O_CREAT: If the message queue does not exist, then create a new, or has no effect, equivalent to open O_EXCL Must be used in conjunction with O_CREAT, if the message queue already exists, returns an error, errno = EEXIST O_NONBLOCK Read the message queue, the default is blocked, i.e., send, if the queue is full will be blocked, When recv, if the queue is empty, will be blocked. Setting the O_NONBLOCK, if abnormal, the process directly returns an error, errno = EAGAIN
attr set the queue parameters, attr == NULL or the default parameters.
(2)mq_receive
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio); #include <time.h> #include <mqueue.h> ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);
The highest priority, oldest news from the team,
Output in msg_ptr,
msg_len the specified len msg_ptr,
msg_len must be greater than the size of the message queue entries (obtained by mq_getattr)
If the queue is empty, The default block until not empty, or signal interruption (returns an error, errno == EINTR), Set O_NONBLOCK, direct returns an error (errno == EAGAIN), Use mq_timedreceive, you can set the blocking time (absolute time)
return value:
It returns the number of bytes successfully received
(3)mq_getattr
int mq_getattr(mqd_t mqdes, struct mq_attr *attr); int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);
struct mq_attr { long mq_flags; /* Flags: 0 or O_NONBLOCK */ long mq_maxmsg; /* Max. # of messages on queue */ long mq_msgsize; /* Max. message size (bytes) */ long mq_curmsgs; /* # of messages currently in queue */ };
When new queue mq_attr are initialized.
mq_flags
Only display 0 or O_NONBLOCK
mq_maxmsg
Queue up to the number of messages
mq_msgsize
The maximum length of the message queue
mq_curmsgs
The current number of messages queue
mq_setattr can only be set mq_flags add O_NONBLOCK
(4)mq_close
int mq_close(mqd_t mqdes);
Close message queue descriptor.
And close the notification request is turned on, so that other threads can apply for notification request.
Auto Close message queue descriptor at the end of the process or exec.
(5)mq_unlink
mqd_t mq_unlink(const char *name);
Remove the message queue name,
When the queue is open all processes have closed the queue, the queue themselves destroyed.
3. Application
(A) receiving simple
#include <stdlib.h> #include <errno.h> #include <stdio.h> #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <mqueue.h> #define MQ_NAME "/mq_test" int main () { struct mq_attr attr = {0}; mqd_t mqid; int mq_len = 60, bytes; char *buf; attr.mq_msgsize = mq_len; attr.mq_maxmsg = 10 ; __again_open__: if (0 > (mqid = mq_open("/mq_test", O_RDONLY | O_CREAT | O_EXCL, 0777, &attr))) { if (errno == EEXIST) { mq_unlink(MQ_NAME); goto __again_open__; } perror("mq_open"); return -1; } if (0 > (buf = (char *)malloc(mq_len))) { perror("malloc"); return -1; } __again_recv__: if (0 > (bytes = mq_receive(mqid, buf, mq_len, NULL))) { if (errno == EINTR) goto __again_recv__; perror("mq_receive"); return -1; } printf("recv %d bytes : %s\n", bytes, buf); goto __again_recv__; return 0; }
(2) simply send
#include <string.h> #include <errno.h> #include <stdio.h> #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <mqueue.h> #define MQ_NAME "/mq_test" int main(int argc, char **argv) { int bytes, msg_len; mqd_t mqid; struct mq_attr attr; char *msg = argv[1]; if (0 > (mqid = mq_open(MQ_NAME, O_WRONLY | O_NONBLOCK))) { perror("mq_open"); return -1; } __again__: if (0 > (bytes = mq_send(mqid, msg, strlen(msg), 10))) { if (errno == EAGAIN) { usleep(100); goto __again__; } perror("mq_send"); return -1; } printf("success to send %d bytes\n", bytes); return 0; }
-------------- POSIX message queue and an asynchronous notification
POSIX message queues with respect to different queues SystemV important message:
POSIX message queues and thread support asynchronous notification signal.
1.API
mqd_t mq_notify (mqd_t mqdes, const struct sigevent notification *);
Thread or revoke a registration for message notification.
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 */ };
sigev_notify
It is used to specify notification method
SIGEV_NONE, specify this thread to accept the notice, but after the incident, will not be notified
SIGEV_SIGNAL: Use signaling
SIGEV_THREAD: Use thread notifies
sigev_signo
If signaling, it is used to specify notification signal
sigev_value
If signaled, and the SA_SIGINFO sigaction specified, the reference for the signal transmission
If a thread notification, the thread used for mass participation
sigev_notify_function:
Specify the thread start function
sigev_notify_atrributes:
Specified thread property, set using pthread_attr_init
Only one thread / Register notice on the process.
Only when the message queue is empty, when the team news, release notification.
A registration notification, the notification will only once, after the notification is removed.
When the message queue is blocking state, and there are processes or threads are recv, namely blocking In the above is not sent notification (recommended NONBLOCK queue).
3. Application
#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 Sigvatur 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 */ }
#include <unistd.h> #include <errno.h> #include <stdio.h> #include <signal.h> #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <mqueue.h> #define MQ_NAME "/mq_test" int g_catch_usr1_flag; void catch_usr1(int sig) { g_catch_usr1_flag = 1; } int main () { int msg_len = 256, bytes; struct mq_attr attr; mqd_t mqid; struct sigevent notification; struct sigaction act; char msg[msg_len + 1]; attr.mq_maxmsg = 10 ; attr.mq_msgsize = msg_len; __try_open__: if (0 > (mqid = mq_open(MQ_NAME, O_RDONLY | O_CREAT | O_EXCL | O_NONBLOCK, 0777, &attr))) { if (errno == EEXIST) { if (0 > mq_unlink(MQ_NAME)) { perror("mq_unlink"); return -1; } goto __try_open__; } perror("mq_open"); } signal(SIGUSR1, catch_usr1); notification.sigev_notify = SIGEV_SIGNAL; notification.sigev_signo = SIGUSR1; if (0 > mq_notify(mqid, ¬ification)) { perror("mq_notify"); return -1; } while (1) { if (0 == g_catch_usr1_flag) { usleep(300); continue; } g_catch_usr1_flag = 0; if (0 > mq_notify(mqid, ¬ification)) { perror("mq_notify"); return -1; } if (0 > (bytes = mq_receive(mqid, msg, msg_len, NULL))) { perror("mq_receive"); return -1; } msg[bytes] = 0; printf("recv %d bytes : %s\n", bytes, msg); } return 0; }