Linux inter-process communication (IPC) Programming Practice (12) Posix message queue-use of basic APIs

Source: Internet
Author: User

Linux inter-process communication (IPC) Programming Practice (12) Posix message queue-use of basic APIs

Difference between posix message queue and system v Message Queue:

(1) reading a posix Message Queue always returns the earliest message with the highest priority. Reading A system v Message Queue can return messages with any specified priority.
(2) When a message is placed in an empty queue, the posix Message Queue can generate a signal or start a thread. The system v Message Queue does not provide a similar mechanism.

Each message in a queue has the following attributes:

1. An unsigned integer priority (posix) or a long integer (system v)
2. The length of the Data part of the message (it can be 0)
3. Data itself (if the length is greater than 0)

Posix Message Queue operation functions are as follows:

1. Create/obtain a Message Queue

Mqd_t mq_open (const char * name, int oflag); // used to open a Message Queue mqd_t mq_open (const char * name, int oflag, mode_t mode, struct mq_attr * attr );

Parameters:

Name: name of the message queue;

Oflag: it is of the open function type. It can be O_RDONLY, O_WRONLY, O_RDWR, or O_CREAT, O_EXCL, or O_NONBLOCK.

Mode: If oflag specifies O_CREAT, you must specify the mode parameter;

Attr: Specifies the attributes of the message queue;

Return Value:

Success: the message queue file descriptor is returned;

Failed:-1 is returned;

Note-Posix IPC name restrictions:

1. It must start with "/" and cannot be followed by "/", for example:/file-name;

2. The name length cannot exceed NAME_MAX.

3. Link with-lrt (use the real-time Link Library-lrt in Makefile)

2. Close A Message Queue

#include    
 
  int mq_close(mqd_t mqdes);
 

Return Value: 0 for success and-1 for error.
Function: Disable an opened message queue.

Note: System V does not have this function to call

3. Delete A Message Queue

Int mq_unlink (const char * name);/** System V Message Queue uses the msgctl function and specifies cmd as IPC_RMID to implement int msgctl (int msqid, int cmd, struct msqid_ds * buf );**/
Return Value: 0 for success and-1 for Error
Function: deletes a message queue from the system.

Comprehensive use of the above three functions:
int main()  {      mqd_t mqid = mq_open("/abc", O_CREAT|O_RDONLY, 0666, NULL);      if (mqid == -1)          err_exit("mq_open error");      cout << "mq_open success" << endl;      mq_close(mqid);      mq_unlink("/abc");      cout << "unlink success" << endl;  }
4. Get/Set message queue attributes
#include    
 
  int mq_getattr(mqd_t mqdes, struct mq_attr *attr);int mq_setattr(mqd_t mqdes, const struct mq_attr *attr, struct mq_attr *attr);
 
Returns: 0 for success and-1 for Error

Parameters:

Newattr: attributes to be set

Oldattr: original attribute

Each message queue has four attributes:
struct mq_attr{    long mq_flags;      /* message queue flag : 0, O_NONBLOCK */    long mq_maxmsg;     /* max number of messages allowed on queue*/    long mq_msgsize;    /* max size of a message (in bytes)*/    long mq_curmsgs;    /* number of messages currently on queue */};

int main(int argc,char **argv)  {      mqd_t mqid = mq_open("/test", O_RDONLY|O_CREAT, 0666, NULL);      if (mqid == -1)          err_exit("mq_open error");        struct mq_attr attr;      if (mq_getattr(mqid, &attr) == -1)          err_exit("mq_getattr error");      cout << "Max messages on queue: " << attr.mq_maxmsg << endl;      cout << "Max message size: " << attr.mq_msgsize << endl;      cout << "current messages: " << attr.mq_curmsgs << endl;        mq_close(mqid);      return 0;  }  
Compare System V:

Use the msgctl function and specify cmd as IPC_STAT/IPC_SET.

Int msgctl (int msqid, int cmd, struct msqid_ds * buf );

In addition, each message has a priority, which is an unsigned integer smaller than MQ_PRIO_MAX.
# Define MQ_PRIO_MAX 32768

5. Send/read messages

#include    
 
  int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio);ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *priop);
 

Return Value: 0 for success and-1 for Error

Return: the number of bytes in the message when the message succeeds. The error is-1.
Parameter: the last one is the priority of the message.

Message Queue restrictions:
MQ_OPEN_MAX: Maximum number of message queues that a process can open simultaneously
MQ_PRIO_MAX: the maximum priority of any message plus 1

/** Example: send a message to the Message Queue. prio needs to read **/struct Student {char name [36]; int age;} from the command line parameters ;}; int main (int argc, char ** argv) {if (argc! = 2) err_quit ("./send
 
  
"); Mqd_t mqid = mq_open ("/test ", O_WRONLY | O_CREAT, 0666, NULL); if (mqid =-1) err_exit (" mq_open error "); struct Student stu = {"xiaofang", 23}; unsigned prio = atoi (argv [1]); if (mq_send (mqid, (const char *) & stu, sizeof (stu), prio) =-1) err_exit ("mq_send error"); mq_close (mqid); return 0 ;}
 
/** Example: get the message from the Message Queue **/int main (int argc, char ** argv) {mqd_t mqid = mq_open ("/test", O_RDONLY ); if (mqid =-1) err_exit ("mq_open error"); struct Student buf; int nrcv; unsigned prio; struct mq_attr attr; if (mq_getattr (mqid, & attr) =-1) err_exit ("mq_getattr error"); if (nrcv = mq_receive (mqid, (char *) & buf, attr. mq_msgsize, & prio) =-1) err_exit ("mq_receive error"); cout <"receive" <nrcv <"bytes, priority: "<prio <", name: "<buf. name <", age:" <buf. age <endl; mq_close (mqid); return 0 ;}
6. Create/delete a message Arrival notification event
#include    
 
  int mq_notify(mqd_t mqdes, const struct sigevent *notification);
 
Return Value: 0 for success and-1 for Error
Function: Creates or deletes asynchronous event notifications for a specified queue.

Sigev_notify indicates the notification method. Generally, two values are used: SIGEV_SIGNAL, which is notified by signal; SIGEV_THREAD, which is notified by thread.

If the notification is sent as a signal, you need to set two parameters:

Sigev_signo: signal code

Sigev_value: additional signal data (real-time signal)

If the notification is sent as a thread: you need to set the following two parameters:

Sigev_policy_function

Sigev_policy_attributes

union sigval{    int sival_int;      /* Integer value */    void *sival_ptr;    /* pointer value */};struct sigevent{    int     sigev_notify;   /* SIGEV_{ NONE, ISGNAL, THREAD} */    int     sigev_signo;    /* signal number if SIGEV_SIGNAL */    union sigval sigev_value;   /* passed to signal handler or thread */    void    (*sigev_notify_function)(union sigval);    pthread_attr_t *sigev_notify_attribute;}; 

Parameter sevp:

NULL: indicates that the registered notification is revoked;

Non-empty: indicates that when a message arrives and the message queue is empty, the message will be notified;

Notification method:

1. generate a signal and bind it to itself

2. Create a thread and execute the specified function

Note: This registration method only generates Message notification events when the message queue is from empty to non-empty, and this registration method is one-time!

** Posix IPC features, System V does not **/
/** Example: run the following program several times, especially when the message queue is "from empty to non-empty", multiple times "from empty to non-empty ", when the program is run when the message queue is not empty, observe the state of the program; **/mqd_t mqid; long size; void sigHandlerForUSR1 (int signo) {// transfers data reading to the response function of SIGUSR1 to struct Student buf; int nrcv; unsigned prio; if (nrcv = mq_receive (mqid, (char *) & buf, size, & prio) =-1) err_exit ("mq_receive error"); cout <"receive" <nrcv <"bytes, priority: "<prio <", name: "<buf. name <", age:" <buf. age <endl;} int main (int argc, char ** argv) {// install the signal response function if (signal (SIGUSR1, sigHandlerForUSR1) = SIG_ERR) err_exit ("signal error"); mqid = mq_open ("/test", O_RDONLY); if (mqid =-1) err_exit ("mq_open error "); // obtain the maximum message length struct mq_attr attr; if (mq_getattr (mqid, & attr) =-1) err_exit ("mq_getattr error"); size = attr. mq_msgsize; // register the message Arrival notification event struct sigevent; event. sigev_notify = SIGEV_SIGNAL; // specify to notify the event by signal. sigev_signo = SIGUSR1; // specify to notify if (mq_notify (mqid, & event) =-1) err_exit ("mq_notify error") with sigev_signo; // an endless loop, wait for the signal to arrive while (true) pause (); mq_close (mqid); return 0 ;}
/** Example: Register notify multiple times so that you can receive messages multiple times, but still cannot receive messages from non-empty queues. The program transformation is as follows: **/mqd_t mqid; long size; struct sigevent event; void sigHandlerForUSR1 (int signo) {// note: the message is registered before it is read, // otherwise, the program will not be able to sense a process in which the message queue "from blank to non-empty" changes if (mq_notify (mqid, & event) =-1) err_exit ("mq_policy error"); // transfers data reading to the response function of SIGUSR1 to struct Student buf; int nrcv; unsigned prio; if (nrcv = mq_receive (mqid, (char *) & buf, size, & prio) =-1) err_exit ("mq_receive error "); cout <"receive" <nrcv <"bytes, priority:" <prio <", name:" <buf. name <", age:" <buf. age <endl;} int main (int argc, char ** argv) {// install the signal response function if (signal (SIGUSR1, sigHandlerForUSR1) = SIG_ERR) err_exit ("signal error"); mqid = mq_open ("/test", O_RDONLY); if (mqid =-1) err_exit ("mq_open error "); // obtain the maximum message length struct mq_attr attr; if (mq_getattr (mqid, & attr) =-1) err_exit ("mq_getattr error"); size = attr. mq_msgsize; // registers the notification event for message arrival. sigev_notify = SIGEV_SIGNAL; // specify to notify the event by signal. sigev_signo = SIGUSR1; // specify to notify if (mq_notify (mqid, & event) =-1) err_exit ("mq_notify error") with sigev_signo; // an endless loop, wait for the signal to arrive while (true) pause (); mq_close (mqid); return 0 ;}

Mq_policy:

1. Only one process can be registered at any time to receive notifications from a given queue;

2. when a message arrives in a previously empty queue and a process is registered to receive notifications from the queue, the notification is sent only when no thread is blocked by the mq_receive call of the queue;

3. when a notification is sent to its registration process, the registration of the process is revoked. the process must call mq_notify again to re-register (if needed), but note that re-register should be placed before the message is read from the message queue, rather than after (like the sample program );

Asynchronous signal security functions
#include    
 
  int sigwait(const sigset_t *set, int *sig);
 

You can use the sigwait function to replace the signal notification of the signal processing program, block the signal to a function, and only wait for the signal to be submitted. Use sigwait to implement the above program as follows:

# Include
 
  
# Include
  
   
# Include
   
    
# Include
    
     
# Include
     
      
# Include
      
        # Include
       
         Int main (int argc, char * argv []) {mqd_t mqd; int signo; void * buff; ssize_t n; sigset_t newmask; struct mq_attr attr; struct sigsievent GeV; if (argc! = 2) {printf ("usage: mqnotify
        
          "); Exit (0);} mqd = mq_open (argv [1], O_RDONLY); mq_getattr (mqd, & attr); buff = malloc (attr. mq_msgsize); sigemptyset (& newmask); sigaddset (& newmask, SIGUSR1); sigprocmask (SIG_BLOCK, & newmask, NULL); sigev. sigev_notify = SIGEV_SIGNAL; sigev. sigev_signo = SIGUSR1; if (mq_notify (mqd, & sigev) =-1) {perror ("mq_policy error"); exit (-1) ;}for (;;) {sigwait (& newmask, & signo); // block and wait for this signal if (signo = SIGUSR1 ){ Mq_policy (mqd, & sigev); while (n = mq_receive (mqd, buff, attr. mq_msgsize, NULL)> = 0) printf ("read % ld bytes \ n", (long) n); if (errno! = EAGAIN) {perror ("mq_receive error"); exit (-1) ;}} eixt (0 );}
        
       
      
     
    
   
  
 
Start the thread to process message notifications. The program is as follows:
#include 
 
  #include 
  
   #include 
   
    #include 
    
     #include 
     
      #include 
      
       #include 
       
        mqd_t mqd;struct mq_attr attr;struct sigevent sigev;static void notify_thread(union sigval);int main(int argc,char *argv[]){ if(argc != 2) { printf("usage :mqnotify 
        
         "); exit(0); } 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; if(mq_notify(mqd,&sigev) == -1) { perror("mq_notify error"); exit(-1); } for(; ;) { pause(); } eixt(0);}static void notify_thread(union sigval arg){ ssize_t n; void *buff; printf("notify_thread started\n"); buff = malloc(attr.mq_msgsize); mq_notify(mqd,&sigev); while((n = mq_receive(mqd,buff,attr.mq_msgsize,NULL))>=0) printf("read %ld bytes\n",(long) n); if(errno != EAGAIN) { perror("mq_receive error"); exit(-1); } free(buff); pthread_exit(NULL);}
        
       
      
     
    
   
  
 

Appendix-view the created Posix Message Queue

# It exists in a Virtual File System and needs to be mounted to the system for viewing

Mounting the message queue filesystem On Linux, message queues are created in a virtual filesystem.

(Other implementations may also provide such a feature, but the details are likely to differ.) This

File system can be mounted (by the superuser, note that only the root user can be used) using the following commands:

Mkdir/dev/mqueue

Mount-t mqueue none/dev/mqueue

You can also use cat to view the status of the Message Queue. rm is deleted:

Cat/dev/mqueue/abc

Rm abc

You can also umount the File System

Umount/dev/mqueue

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.