The main differences between POSIX Message Queuing and System V Message Queuing are:
1. The total number of reads to the POSIX queue returns the highest priority to the oldest message, and the SV queue to read can return any specified priority message
2. When a message is placed into an empty queue, POSIX allows a signal to be generated or a thread to start, System V does not provide this mechanism
Properties of the message:
1. The priority of an unsigned integer (POSIX) or the type of a long integer (SV)
2. The data part length of the message (can be 0)
3. The data itself (if the length is greater than 0)
POSIX Message Queuing Summary:
Mq_open Create a new queue or open a queue that already exists
Mq_close Close Queue
Mq_unlink Delete queue name, delete queue
Mq_send placing messages into queues
Mq_receive read messages from a queue
Mq_setattr and mq_getattr querying and setting the properties of a queue
Mq_notify allows a signal or thread to be registered, send a signal or activate a thread when a message is placed in an empty queue
Each message is given a small integer priority, and mq_receive always returns the oldest message with the highest priority
Limit:
/proc/sys/fs/mqueue/msg_max 10
/proc/sys/fs/mqueue/msgsize_max 8192
/proc/sys/fs/mqueue/queues_max 256
Create a new Message queue or open a message queue that already exists
<mqueue.h> Note: Compile plus-LRT
<fcntl.h>
<sys/stat.h>
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);
Successful return descriptor, failure return-1 and set errno
Name: Must BE/start!!!
Oflag:o_rdonly, O_wronly, O_rdwr, O_creat, O_EXCL, O_nonblock
Closes Message Queuing, but cannot delete it
mqd_t mq_close (mqd_t mqdes);
Successful return 0, failure return-1
Deleting a message queue does not necessarily delete the message queue immediately, but the queue name is immediately deleted
mqd_t mq_unlink (const char *name);
Successful return 0, failure return-1
When a process has not closed this message queue, the queue is not deleted immediately when Mq_unlink is called, and the queue is deleted when the last process closes the queue
int flags;
mqd_t MQD;
Flags = O_RDWR | O_creat | O_EXCL;
MQD = Mq_open ("/tmp.111", Flags, 0644, NULL);
if (Mqd = = (mqd_t)-1) {
Perror ("Mq_open");
return 1;
}
Properties of Message Queuing
Mq_getattr mq_setattr
mqd_t mq_getattr (mqd_t mqdes, struct mq_attr *attr);
mqd_t mq_setattr (mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);
Successful return 0, failure return-1
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 */
};
Mq_setattr can only modify the Mq_flags property, Maxmsg and Msgsize are set when Mq_open
mqd_t MQD;
struct mq_attr attr;
MQD = Mq_open (argv[1], o_rdonly);
Mq_getattr (MQD, &attr);
printf ("Maxmsg=%ld, Msgsize=%ld, curmsgs=%ld\n",
Attr.mq_maxmsg, Attr.mq_msgsize, ATTR.MQ_CURMSGS);
Mq_close (MQD);
Send and receive messages
Mq_send mq_receive
Mq_receive returns the oldest message of the highest priority in the queue, and the priority can be returned with the contents of the message and its length
ssize_t mq_receive (mqd_t mqdes, Char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
The length of the message that was successfully returned, the actual length of the message, not including the message header; failed return-1
Msg_len indicates the length of the msg_ptr and must be greater than or equal to Mq_msgsize
If Msg_prio is not NULL, the function returns the priority of the message
If the queue is empty, the call is blocked, and if the queue is set 0_nonblock, the call returns immediately Eagain
Add a message to the queue
mqd_t MQD;
Char *msg;
size_t Len;
unsigned int prio;
len = 100;
Prio = 5;
MQD = Mq_open ("/abc.123", o_wronly);
msg = (char *) malloc (len);
memset (msg, 0, Len);
Mq_send (MQD, MSG, Len, prio);
Reads a message from the queue
mqd_t MQD;
Char *msg;
size_t Len;
int n;
unsigned int prio;
struct mq_attr attr;
MQD = Mq_open ("/abc.123", o_rdonly);
Mq_getattr (MQD, &attr);
len = attr.mq_msgsize;
msg = (char *) malloc (len);
memset (msg, 0, Len);
n = mq_receive (MQD, MSG, Len, &prio);
printf ("read%ld bytes, priority=%u\n", (long) n, Prio);
Queue limit
long int open_max = sysconf (_sc_mq_open_max); -1
long int prio_max = sysconf (_sc_mq_prio_max); 32768
Message notification
Notifies the process when a message is placed toward the empty queue
There are 2 ways to advertise:
1. Generate a signal
2. Create a thread to execute a specified function
mqd_t mq_notify (mqd_t mqdes, const struct sigevent *notification);
Successful return 0, failure return-1
Create or delete asynchronous event notifications for a queue
1. If notification is not NULL, the current process expects to be notified when a message arrives and the queue is previously empty, and the process is registered as a notification to receive the queue
2. If notification is empty and the current process is currently registered as a notification to receive the queue, the existing registration will be revoked
3. At any moment only one process can be registered as a notification of the receive queue
4. When a message arrives at an empty queue and there is already a process registered as a notification to receive the queue, the notification is sent only if no thread is blocking the mq_receive call to that queue. That is, blocking in mq_receive calls takes precedence over the registration of any notification
5. When the notification has been sent to its registration process, its registration is revoked. The process must call Mq_notify again to re-register
6. Notifications are not sent when Mq_notify is called but the queue is not empty, and notifications are sent when the queue becomes empty and a message is queued
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:sigev_none,sigev_signal,sigev_thread
Signal notification using non-blocking mq_receive
Volatile sig_atomic_t Mqflag;
static void sig_usr1 (int);
int main (int argc, char *argv[])
{
mqd_t MQD;
void *buf;
ssize_t N;
sigset_t Zeromask, Newmask, Oldmask;
struct mq_attr attr;
struct Sigevent Sigev;
ASSERT (argc = = 2);
MQD = Mq_open (argv[1], o_rdonly| O_nonblock);
Mq_getattr (MQD, &attr);
BUF = malloc (attr.mq_msgsize);
Sigemptyset (&zeromask);
Sigemptyset (&newmask);
Sigemptyset (&oldmask);
Sigaddset (&newmask, SIGUSR1);
Signal (SIGUSR1, SIG_USR1);
Sigev.sigev_notify = sigev_signal;
Sigev.sigev_signo = SIGUSR1;
Mq_notify (MQD, &sigev);
for (;;) {
Sigprocmask (Sig_block, &newmask, &oldmask);
while (Mqflag = = 0)
Sigsuspend (&zeromask);
Mqflag = 0;
Mq_notify (MQD, &sigev);
while ((n = mq_receive (MQD, buf, Attr.mq_msgsize, NULL)) >= 0) {
printf ("Read%ld bytes\n", (long) n);
}
if (errno! = Eagain)
Die ("mq_receive");
Sigprocmask (Sig_unblock, &newmask, NULL);
}
return 0;
}
static void sig_usr1 (int signo)
{
Mqflag = 1;
Return
}
Signal notification using sigwait instead of signal processing program
#include <signal.h>
int sigwait (const sigset_t *set, int *sig);
Successfully returns 0 and sets the sig for the received signal; failure return error code
int main (...)
{
...
Sigemptyset (&newmask);
Sigaddset (&newmask, SIGUSR1);
Sigprocmask (Sigblock, &newmask, NULL);
Sigev.sigev_notify = sigev_signal;
Sigev.sigev_signo = SIGUSR1;
Mq_notify (MQD, &sigev);
for (;;) {
Sigwait (&newmask, &signo);
if (Signo = = SIGUSR1) {
Mq_notify (MQD, &sigev);
while ((n = mq_receive (MQD, buf, Len, NULL)) >=0) {
printf ("Read%ld bytes\n", N);
}
if (errno! = Eagain)
Die ("mq_receive");
}
}
...
}
POSIX Message Queuing with Select
int pfds[2];
static void sig_usr1 (int);
int main (int argc, char *arg[])
{
int FDS;
char c;
Fd_set RfDs;
mqd_t MQD;
void *buf;
ssize_t N;
size_t Len;
struct mq_attr attr;
struct Sigevent Sigev;
Asset (ARGC = = 2);
MQD = Mq_open (argv[1], o_rdonly| O_nonblock);
Mq_getattr (MQD, &attr);
len = attr.mq_msgsize;
BUF = malloc (len);
Pipe (PFDS);
Set up signal handlers, set up notifications
Signal (SIGUSR1, SIG_USR1);
Sigev.sigev_notify = sigev_signal;
Sigev.sigev_signo = SIGUSR1;
Mq_notify (MQD, &sigev);
Fd_zero (&rfds);
for (;;) {
Fd_set (Pfds[0], &rfds);
Nfds = Select (pfds[0]+1, &rfds, NULL, NULL, NULL);
if (Fd_isset (Pfds[0], &rfds)) {//Pipe readable
Read (Pfds[0], &c, 1);
Mq_notify (MQD, &sigev);
while ((n = mq_receive (MQD, buf, Len, NULL)) >= 0) {
printf ("Read%ld bytes\n", (long) n);
}
if (errno! = Eagain)
Die ("mq_receive");
}
}
return 0;
}
static void sig_usr1 (int signo)
{
Write (Pfds[1], "", 1); Functions of asynchronous signal processing security
Return
}
After you receive the notification, start a thread, receive the message, and then end the process
#include <pthread.h>
#include <mqueue.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DIE (msg) {perror (msg); exit (exit_failure);}
static void Tfunc (Union sigval SV)/* Thread start function */
{
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) die ("mq_getattr");
BUF = malloc (attr.mq_msgsize);
if (buf = = NULL) die ("malloc");
NR = mq_receive (Mqdes, buf, Attr.mq_msgsize, NULL);
if (nr = =-1) die ("mq_receive");
printf ("Read%ld bytes from mq0\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) die ("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) die ("mq_notify");
Pause (); /* Process would be is terminated by thread function */
return 0;
}
Start a new thread
mqd_t MQD;
struct mq_attr attr;
struct Sigevent Sigev;
static void Notify_thread (Union sigval);
int main (int argc, char *argv[])
{
ASSERT (argc = = 2);
MQD = Mq_open (argv[1], o_rdonly| O_nonblock);
Mq_getattr (MQD, &attr);
Sigev.sigev_notify = Sigev_thread;
Sigev.sigev_value.sival_ptr = NULL;
Sigev.sigev_notify_function = Notify_thread;
Sigev.sigev_notify_attributes = NULL;
Mq_notify (MQD, &sigev);
for (;;)
Pause ();
return 0;
}
static void Notify_thread (Union sigval Arg)
{
ssize_t N;
size_t Len;
void *buf;
len = attr.mq_msgsize;
printf ("Notify_thread started\n");
BUF = malloc (len);
Mq_notify (MQD, &sigev);
while ((n = mq_receive (MQD, buf, Len, NULL)) >= 0) {
printf ("Read%ld bytes\n", (long) n);
}
if (errno! = Eagain)
Die ("mq_receive");
Free (BUF);
Pthread_exit (NULL);
}
POSIX real-time signal
The UNIX signal is divided into two large groups:
Real-time signal: Sigrtmin--sigrtmax
Other signals: SIGINT, Sigquit, SIGKILL, ...
The real-time behavior of the signal depends on Sa_siginfo
Real-time behavior includes the following characteristics:
1. The signal is queued, that is, if a signal is generated 3 times, it is submitted 3 times. Queue in FIFO order
2. When there are multiple sigrtmin to Sigrtmax in the range of the blocking signal queuing, the lower value of the signal is preceded by a higher value of the signal submitted (note: Linux on the contrary)
3. When a non-real-time signal is submitted, the only parameter that is transmitted to it is the value of the signal, and the real-time signal transmits more information than the other signals
4. Some new functions work with real-time signals, such as sigqueue to replace kill
View the real-time signal submission sequence
static void Sig_rt (int, siginfo_t *, void *);
int main (void)
{
int I, J;
pid_t pid;
sigset_t Newset;
Union Sigval Val;
printf ("sigrtmin=%d, sigrtmax=%d\n", (int) sigrtmin, (int) sigrtmax);
PID = fork ();
if (PID < 0) die ("fork");
else if (PID = = 0) {
/* Block 3 real-time signals */
Sigemptyset (&newset);
Sigaddset (&newset, sigrtmin);
Sigaddset (&newset, sigrtmin+1);
Sigaddset (&newset, sigrtmin+2);
Sigprocmask (Sig_block, &newset, NULL);
Signal_rt (Sigrtmin, SIG_RT);
Signal_rt (sigrtmin+1, SIG_RT);
Signal_rt (sigrtmin+2, SIG_RT);
Sleep (6);
Sigprocmask (Sig_unblock, &newset, NULL);
Sleep (3);
Exit (0);
}
else {
Sleep (3);
for (i=sigrtmin; i<=sigrtmin+2; i++) {
for (j=0; j<=2; J + +) {
Val.sival_int = j;
Sigqueue (PID, I, Val);
printf ("Send signal signo=%d, val=%d\n", I, j);
}
}
Exit (0);
}
}
static void Sig_rt (int signo, siginfo_t *info, void *context)
{
printf ("Receive signal signo=%d, code=%d, ival=%d\n",
Signo, Info->si_code, Info->si_value.sival_int);
}
typedef void SIGFUNC_RT (int, siginfo_t *, void *);
Sigfunc_rt *signal_rt (int signo, Sigfunc_rt *func)
{
struct Sigaction Act, oact;
Act.sa_sigaction = func;
Sigemptyset (&act.sa_mask);
Act.sa_flags = Sa_siginfo; /* real-time signal must be specified */
if (Signo = = SIGALRM) {
#ifdef Sa_interrupt
Act.sa_flags |= Sa_interrupt;
#endif
}
else {
#ifdef Sa_restart
Act.sa_flags |= Sa_restart;
#endif
}
if (Sigaction (Signo, &act, &oact) < 0)
Return (SIGFUNC_RT *) Sig_err;
Else
return oact.sa_sigaction;
}
The output is as follows:
[Email protected] unp]#./rtsig
Sigrtmin=34, sigrtmax=64
Send Signal signo=34, val=0
Send Signal signo=34, val=1
Send Signal signo=34, val=2
Send Signal signo=35, val=0
Send Signal signo=35, val=1
Send Signal signo=35, val=2
Send Signal signo=36, val=0
Send Signal signo=36, val=1
Send Signal signo=36, val=2
Receive signal signo=36, Code=-1, ival=0
Receive signal signo=36, Code=-1, ival=1
Receive signal signo=36, Code=-1, ival=2
Receive signal signo=35, Code=-1, ival=0
Receive signal signo=35, Code=-1, ival=1
Receive signal signo=35, Code=-1, ival=2
Receive signal signo=34, Code=-1, ival=0
Receive signal signo=34, Code=-1, ival=1
Receive signal signo=34, Code=-1, ival=2
struct Sigaction {
void (*sa_handler) (int);
void (*sa_sigaction) (int, siginfo_t *, void *);
sigset_t Sa_mask;
int sa_flags;
void (*sa_restorer) (void); /* was abandoned! */
};
The real-time signal is reliable because during the time the process blocks the signal, all real-time signals to the process are queued, and the non-real-time signal is combined into a single signal. The early kill function can only send a specific signal to a particular process, and early signal processing functions cannot accept additional data. Siqueue and Sigaction solved the problem.
In the following example, the process first masks the SIGINT and sigrtmin two signals, wherein the SIGINT is a real-time signal, and the sigrtmin is a real-time signal, then the process of sleep, after the completion of sleep and then contact the shielding of the two signals, at this time can be compared to the two types of signal processing is the same.
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
void Sig_handler (int, siginfo_t*, void*);
int main (int argc,char *argv[])
{
struct Sigaction Act;
sigset_t Newmask, Oldmask;
int RC;
Sigemptyset (&newmask);
/* Add a non-real-time signal to the signal set */
Sigaddset (&newmask, SIGINT);
/* Add a real-time signal to the signal set */
Sigaddset (&newmask, sigrtmin);
/* shield real-time signal sigrtmin */
Sigprocmask (Sig_block, &newmask, &oldmask);
Act.sa_sigaction = Sig_handler;
Act.sa_flags = Sa_siginfo;
if (Sigaction (SIGINT, &act, NULL) < 0) {
printf ("Install signal error\n");
}
if (Sigaction (Sigrtmin, &act, NULL) < 0) {
printf ("Install signal error\n");
}
printf ("pid =%d\n", Getpid ());
/* Process sleep, all real-time signals sent to the process during this time will be queued, no loss of signal */
Sleep (20);
/* Unblock the sigrtmin signal, the signal processing function will be called */
Sigprocmask (Sig_setmask, &oldmask, NULL);
return 0;
}
void Sig_handler (int signo, siginfo_t *info, void *context)
{
if (Signo = = SIGINT)
printf ("Got a common signal\n");
Else
printf ("Got a real Time signal\n");
}
After compiling the program, open a terminal to send the real-time signal.
#./sigqueue_receive
PID = 8871
Process begins to sleep ...
In the new terminal input:
[Email protected]:~/pthreads$ kill-sigrtmin 8871
[Email protected]:~/pthreads$ kill-sigrtmin 8871
[Email protected]:~/pthreads$ kill-sigrtmin 8871
[Email protected]:~/pthreads$ kill-sigrtmin 8871
Send four consecutive sigrtmin, then go back to the previous terminal, press "CTRL + C" four times in a row.
^c^c^c^c
Finally the process wakes up, the entire output is as follows:
PID = 8871
^c^c^c^cgot a real time signal
Got a real time signal
Got a real time signal
Got a real time signal
Got a common signal
Sure enough to receive four real-time signals, and four calls to the signal processing function, and for SIGINT, although also pressed four times "CTRL + C", but the process to do it only once processing. In this example, the real-time signal is sent after the non-real-time signal, so the signal processing function first processing the real
Signal, if only in order to register the signal, this is very good understanding, but change, first press four times "CTRL + C" and then use Kill to send four real-time signals, the results found that the output is still the same, which shows that the real-time signal priority than the non-real-time signal is higher, The signals of each process in the kernel form a doubly linked list, and the real-time signal is not plugged in at the end.
Signal priority: The signal is essentially a soft interrupt, the interrupt has priority, and the signal has priority. If a process has multiple pending signals, for the same pending real-time signal, the kernel submits the signal in the order in which it was sent. If there is more than one pending real-time signal, the larger the value (or number) is delivered first. If there is no unreliable signal and there is a reliable signal (real-time signal), although POSIX does not specify this situation, but the Linux system and most of the POSIX-compliant operating system, the same will be a priority to submit reliable signals. A process if processing sigquit (3), SIGINT (2), SIGHUP (1) (through "kill-l" can see the signal number), then sent to the process sigint,sighup,sigquit, the order of processing will be sigquit, Sigint,sighup, regardless of the order in which the three signals are sent, the order of processing is the same.
POSIX Message Queuing