linux应用 进程间通信之消息队列(POSIX)(下)

mq_notify 

是一个系统调用函数,用于消息队列(Message Queue)的通知机制。

在 POSIX 消息队列中,当消息队列中有消息到达时,通常需要轮询来检查是否有新消息到达,这样会占用 CPU 资源并且效率不高。mq_notify 函数的作用是设置一个异步通知,当消息队列状态发生特定变化(例如消息到达)时,操作系统会发送一个信号给进程,从而实现异步通知。

具体来说,使用 mq_notify 函数时,可以指定一个信号及其处理函数。当消息队列中有新消息到达时,系统会向进程发送指定的信号,并调用预先设置的处理函数。这种方式避免了进程不断轮询消息队列的状态,提高了效率,特别是在需要等待和处理大量消息时。

总结来说,mq_notify 是利用信号机制实现的一种消息队列异步通知方式,是提高程序效率和响应性的重要工具之一

#include <mqueue.h>

int mq_notify(mqd_t mqdes, const struct sigevent *sevp);
  1. mqdes:这是一个消息队列描述符(mqd_t),是调用 mq_open() 打开消息队列后返回的标识符。它指定了要监视的消息队列。

  2. :这是一个指向 struct sigevent 结构的指针,用于指定通知的方式和内容。struct sigevent 结构定义在 <signal.h> 中,包含了如何通知进程的信息,可以通过该结构设置三种通知方式之一   通过发送信号通知进程。通过线程通知进程。通过创建一个新的进程通知进程。

struct sigevent {
    int sigev_notify;               /* 通知方式:SIGEV_SIGNAL, SIGEV_THREAD 或 SIGEV_NONE */
    int sigev_signo;                /* 信号编号 */
    union sigval sigev_value;       /* 传递给进程/线程的值 */
    void (*sigev_notify_function)(union sigval);  /* 信号处理函数 */
    pthread_attr_t *sigev_notify_attributes;       /* 线程属性(如果使用线程通知) */
};

          在调用 mq_notify() 时,通过填充这个结构体来指定如何通知进程,其中 sigev_notify 可以设置为 SIGEV_SIGNAL 表示通过信号通知,sigev_signo 指定信号编号,sigev_notify_function 指定信号处理函数,sigev_notify_attributes 可以设置线程的属性

  1. SIGEV_SIGNAL

    • 这种通知方式表示在发生事件时,操作系统会发送一个信号给进程。
    • 在 struct sigevent 结构中,设置 sigev_notify 为 SIGEV_SIGNAL,并指定 sigev_signo 字段为一个有效的信号编号,如 SIGUSR1 或 SIGUSR2
    • 进程可以通过注册相应的信号处理函数来处理这个信号,从而进行通知事件的处理。
  2. SIGEV_THREAD

    • 这种通知方式表示在发生事件时,操作系统会创建一个新线程来执行预定义的处理函数。
    • 在 struct sigevent 结构中,设置 sigev_notify 为 SIGEV_THREAD,并指定 sigev_notify_function 字段为一个函数指针,该函数将在新线程中执行。
    • 另外,可以设置 sigev_notify_attributes 字段以指定新线程的属性,例如堆栈大小等。
  3. SIGEV_NONE

    • 这种通知方式表示不使用任何特定的通知机制。这通常用于取消之前设置的通知方式。
    • 在 struct sigevent 结构中,设置 sigev_notify 为 SIGEV_NONE 即可。

总结:

  • SIGEV_SIGNAL 表示通过发送信号的方式通知进程。
  • SIGEV_THREAD 表示通过创建新线程并执行函数的方式通知进程。
  • SIGEV_NONE 表示不使用任何通知方式。
#include <mqueue.h>
#include <pthread.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#if 0

mqd_t mq_open(const char *name, int oflag, ...);
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);

int mq_close(mqd_t mqdes);

int mq_unlink(const char *name);

struct mq_attr {
    long mq_flags;       // 消息队列的标志:0 或 O_NONBLOCK
    long mq_maxmsg;      // 消息队列中最大的消息数
    long mq_msgsize;     // 消息队列中单个消息的最大大小
    long mq_curmsgs;     // 消息队列中当前的消息数
};


#endif

#define QUEQUE_NAME "/test_queue"
#define MESSAGE "mqueue,test"
//全局变量的消息队列描述符
mqd_t mqd =-1;

void *send_thread(void *arg)
{
    char message[12] = MESSAGE;
    printf("send buffer is %s\n",message);
    mq_send(mqd,message,strlen(message)+1,0);
    printf("Message sent\n");
    return NULL;

}

 void notify_thread( union sigval sval)
 {
    mqd_t mqd = -1;
    int n_read = -1;
    struct sigevent sev;

    mqd = *((mqd_t *)sval.sival_ptr);
    char buffer[256];
    memset(buffer,0,sizeof(buffer));
    printf("notify_thread started, mqd=%d\n", mqd);
    while(1){
        n_read = mq_receive(mqd,buffer,256,NULL);
        if(n_read >0){
            printf("mq_rcive : buffer is %s,mqd=%d\n",buffer,mqd);
        }
        if(n_read == -1){
            // 如果错误码是EAGAIN,说明队列为空,跳出循环
            if (errno == EAGAIN)
            {
                printf("queue is empty\n");
                break;
            }
            // 否则,打印错误信息,退出程序
            else{
                perror("mq_receive");
                exit(1);
            }

        }
    }
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = notify_thread;
    sev.sigev_notify_attributes = NULL;
    sev.sigev_value.sival_ptr = &mqd;
    if (mq_notify(mqd, &sev) == -1)
    {
        perror("mq_notify");
        exit(1);
    }
 }
int main(){


    pthread_t sender,reciver;


    struct mq_attr attr; //创建消息队列属性结构体变量

    attr.mq_flags = 0; // 消息队列的标志位设置为0
    attr.mq_maxmsg = 10; // 消息队列的最大消息数设置为10
    attr.mq_msgsize = 256;//消息队列的每个消息的最大大小设置为256字节
    attr.mq_curmsgs = 0;// 消息队列的当前消息数设置为0
    //mqd_t mq_open(const char *name, int oflag, mode_t mode,
    //                 struct mq_attr *attr);

    // 打开或创建名为QUEUE_NAME的消息队列,并设置其属性为attr指定的值
    mqd = mq_open(QUEQUE_NAME,O_CREAT|O_RDWR,0666,&attr);
    if(mqd == -1){
        perror("mq_open ");
        return -1;
    }

    struct sigevent sev; // 注册消息队列的通知,使用线程模式,指定回调函数和参数
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = notify_thread;
    sev.sigev_notify_attributes = NULL;
    sev.sigev_value.sival_ptr = &mqd;

    if(mq_notify(mqd,&sev)== -1){
        perror("mq_notify");
        exit(1);
    }

#if 1
    if ( pthread_create(&sender,NULL,send_thread,NULL) != 0){
        printf("send_pthread create error\n");
        perror("send_pthread create");
    }else{
        printf("send_pthread create success\n");
    }
#endif
#if 0
    if ( pthread_create(&reciver,NULL,recive_thread,NULL) != 0){
        printf("recive_thread create error\n");
        perror("recive_thread create");
    }else{
        printf("recive_thread create success\n");
    }
#endif
    pthread_join(sender,NULL);
   // pthread_join(reciver,NULL);

    mq_close(mqd);
    mq_unlink(QUEQUE_NAME);
    return 0;
}

 

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值