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);
mqdes
:这是一个消息队列描述符(mqd_t),是调用mq_open()
打开消息队列后返回的标识符。它指定了要监视的消息队列。:这是一个指向
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
可以设置线程的属性
SIGEV_SIGNAL
:
- 这种通知方式表示在发生事件时,操作系统会发送一个信号给进程。
- 在
struct sigevent
结构中,设置sigev_notify
为SIGEV_SIGNAL
,并指定sigev_signo
字段为一个有效的信号编号,如SIGUSR1
或SIGUSR2
。- 进程可以通过注册相应的信号处理函数来处理这个信号,从而进行通知事件的处理。
SIGEV_THREAD
:
- 这种通知方式表示在发生事件时,操作系统会创建一个新线程来执行预定义的处理函数。
- 在
struct sigevent
结构中,设置sigev_notify
为SIGEV_THREAD
,并指定sigev_notify_function
字段为一个函数指针,该函数将在新线程中执行。- 另外,可以设置
sigev_notify_attributes
字段以指定新线程的属性,例如堆栈大小等。
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;
}