异步通知 mq_notify函数

System V消息队列的问题之一是无法通知一个进程何时在某个队列中放置了一个消息。采用轮询(poling),是对CPU时间的一种浪费。

Posix消息队列容许 异步事件通知,以告知何时有一个消息放置到某个空消息队列中。

该通知有两种方式:当一个消息被放置某个空队列时,要么产生一个信号来通知,要么通过创建一个线程来执行一个特定程序,来完成消息到来时的该做的事情。

这种通知通过调用mq_notify建立

#include <mqueue.h>
int mq_notify(mqd_t mqdes, const struct sigevent* notification);

该函数为指定队列建立或删除异步事件通知

(1).如果notification参数为非空,那么当前进程希望在有一个消息到达所指定的先前为空的对列时得到通知。

(2).如果notification参数为空,而且当前进程被注册为接收指定队列的通知,那么已存在的注册将被撤销。

struct sigevent的结构是:

union sigval {               /*传递的参数*/

    int     sival_int;        /* 信号机制传递的参数 */

    void   *sival_ptr;        /* 若是线程机制传递的参数 */

};

struct sigevent {

    int    sigev_notify;      /* 设置通知机制方法,线程为SIGEV_THREAD,信号为SIGEV_SIGNAL*/

    int    sigev_signo;       /* 若是信号机制,该参数设置为触发的信号 */

    union sigval sigev_value;/* 传递的参数*/

    void (*sigev_notify_function)(union sigval); /* 若是线程机制,该参数为线程函数*/

    void  *sigev_notify_attributes; /* 线程函数的属性 */

};

需要注意的几点:

1.  只需注册一个线程函数。

2.  消息机制触发条件是:在消息队列为空的情况下有数据到来才会触发,当消息队列不为空时,有数据到来不触发。

3.  当消息机制触发后,需要重新注册,在我们的应用中,当线程函数触发后需要重新注册线程函数。在后面的代码中可以看到。

2.      简单示例

#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;  // 传递给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);
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值