POSIX消息队列

消息队列可以认为是一个消息链表,每个消息都是一个记录,它由发送者赋予一个优先级。某个进程往一个消息队列中写入消息之前,不需要另外某个进程在该队列上等待消息的达到,这一点与管道和FIFO相反,与管道和 FIFO的另一区别是消息队列具有随内核的持续性

POSIX消息队列特性:

1.对posix消息队列的读总是返回最高优先级的消息。
2.当往一个空队列放置一个消息时,posix消息队列允许产生一个信号或启动一个线程。

POSIX消息队列函数

1.mqd_t mq_open(...)
2.int mq_close(...)
3.int mq_unlink(...)
4.int mq_getattr(...)
5.int mq_setattr(...)
6.int mq_send(...)
7.int mq_receive(...)
8.int mq_notify(...)

1.使用非阻塞mq_receive的信号通知
#include "unpipc.h"
#include <mqueue.h>
#include <error.h>
volatile sig_atomic_t mqflag;
static void sig_usr1(int);
int
main(int argc, char **argv)
{   
    mqd_t mqd;
    void *buff;
    ssize_t n;
    sigset_t zeromask, newmask, oldmask;
    struct mq_attr attr;
    struct sigevent sigev;
    int rc;
    if( argc != 2 )
        err_quit("usage:mqnotifysig2 <name>");
    mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);//以非阻塞形式打开mq
    rc = Mq_getattr(mqd, &attr);
    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);
    buff = Malloc(attr.mq_msgsize);
    for(; ;)
    {
        Sigprocmask(SIG_BLOCK, &newmask, &oldmask);
        /*若不设置阻塞SIGUSR1,则可能在测试mqflag==0时,在调用sigsuspend之前,
         SIGUSR1信号可能被捕获,并从信号sig_usr1返回,则最终导致sigsuspend将进程
         永远挂起
         */
        while( 0 == mqflag )
            sigsuspend(&zeromask);                      
        mqflag = 0;
        Mq_notify(mqd, &sigev);
        //循环从mqd中读出所有消息,mqd被设置为非阻塞,若无无消息可读
        //则mq_receive立即返回,并设置errno=EAGAIN
        while( (n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0){
            printf("read %ld bytes\n", (long)n );
        }
        if( errno != EAGAIN )  //若errno==EAGAIN,则表明暂无消息可读
            err_sys("mq_receive error\n");
        Sigprocmask(SIG_UNBLOCK, &newmask, NULL);
    }
    Free(buff);
    exit(0);
}
static void sig_usr1(int signo)
{
    mqflag = 1;
    return;
}
2.使用sigwait代替信号处理程序的信号通知
#include "unpipc.h"
#include <mqueue.h>
#include <error.h>
int
main(int argc, char **argv)
{
    int signo;   
    mqd_t mqd;
    void *buff;
    ssize_t n;
    sigset_t newmask;
    struct mq_attr attr;
    struct sigevent sigev;
    if( argc != 2 )
        err_quit("usage:mqnotifysig4 <name>");
    mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);//以非阻塞形式打开mq
    Mq_getattr(mqd, &attr);
    Sigemptyset(&newmask);
    Sigaddset(&newmask, SIGUSR1);
    Sigprocmask(SIG_BLOCK, &newmask, NULL);
    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo = SIGUSR1;
    Mq_notify(mqd, &sigev);
    buff = Malloc(attr.mq_msgsize);
    for(; ;)
    {
       Sigwait(&newmask, &signo);
       if(signo == SIGUSR1 ){
           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 )  //若errno==EAGAIN,则表明暂无消息可读
            err_sys("mq_receive error\n");
       }
    } 
    Free(buff);
    exit(0);
}
3.使用select的posix消息队列
#include "unpipc.h"
#include <mqueue.h>
#include <error.h>
int pipefd[2];//用管道实现统一事件源
static void sig_usr1(int);
int
main(int argc, char **argv)
{
    int     nfds;
    char    c;
    fd_set  rset;
    mqd_t   mqd;
    void    *buff;
    ssize_t n;
    struct mq_attr  attr;
    struct sigevent sigev;
    if(2 != argc )
        err_quit("usage:mqnotifysig5 <name>");
    mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK );//以非阻塞形式打开mq
    Mq_getattr(mqd, &attr);
    buff = Malloc(attr.mq_msgsize);
    Pipe(pipefd);
    Signal(SIGUSR1, sig_usr1);
    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo  = SIGUSR1;
    Mq_notify(mqd, &sigev);
    FD_ZERO(&rset);
    for(; ;)
    {
        FD_SET(pipefd[0], &rset);
        nfds = Select(pipefd[0]+1, &rset, NULL, NULL, NULL);//select监听pipefd[0]描述符
        /*当往空Mq中放入消息时,产生SIGUSR1信号
         * 当SIGUSR1信号被捕获时,信号处理函数往pipefd[1]中写,从而可以监听到pipefd[0]可读
         */
        if(FD_ISSET(pipefd[0], &rset) )
        {
            Read(pipefd[0], &c, 1);
            Mq_notify(mqd, &sigev);     //重新注册notify
            while((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0)
            {
                printf("read %ld bytes\n", (long)n );
            }
            if( errno != EAGAIN )
                err_sys("mq_receive error\n");
        }
    }
  Free( buff );
  exit(0);
}
static void sig_usr1(int signo)//SIGUSER1信号处理函数
{
    Write(pipefd[1], "", 1);//往pipefd[1]中写一个空字符
    return;
}
4.异步通知之设置sigev_notify为SIGEV_THREAD
#include "unpipc.h"
#include <mqueue.h>
#include <error.h>
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 )
        err_quit("usage:notifythread1 <name>");
    mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);
    Mq_getattr(mqd, &attr);

    sigev.sigev_notify = SIGEV_THREAD;//当空mq中存入消息时,启动一个线程(notify_thread)
    sigev.sigev_value.sival_ptr = NULL;//指定线程无参
    sigev.sigev_notify_function = notify_thread;//指定线程函数入口
    sigev.sigev_notify_attributes = NULL;//使用默认线程属性
    Mq_notify(mqd, &sigev);
    for(; ; )
        pause();
    exit(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 )
        err_sys("mq_receive error!\n");
    free( buff );
    pthread_exit(NULL);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值