我正在使用mq_notify
通知消息队列中的事件,但我的注册通知函数未被调用。我错过了什么吗?
我正在粘贴下面的代码段:
static void sigNotifier(union sigval sv)
{
printf ("I'm called.\n");
}
int main()
{
mqd_t queueID = 0;
message_t msg;
int retval;
struct mq_attr attr;
struct sigevent sev;
attr.mq_msgsize = MSG_SIZE;
attr.mq_maxmsg = 30;
errno = 0;
queueID = mq_open(MSG_QUEUE_NAME, O_RDONLY, 0666, &attr);
if (queueID == -1) {
printf ("Message queue open failed: %d\n", errno);
}
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = sigNotifier;
sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_ptr = &queueID;
retval = mq_notify(queueID, &sev);
if (retval < 0) {
printf ("Notification failed: %d\n", errno);
}
while (1);
}
答案 0 :(得分:0)
因为代码是手册页的副本,我会问:
在Linux下,您可以使用select / poll / epoll等待有关队列的通知以及 mqd_t是普通的文件描述符。
答案 1 :(得分:0)
同时检查队列是否已有消息。如果队列中存在消息,则mq_notify()将不会获得通知,直到队列为空,然后新消息进入。 由于队列是跨程序运行的持久性,因此您需要确保在打开之前已在队列上调用mq_unlink()。
答案 2 :(得分:0)
手册页 mq_notify :
1)仅当新消息到达并且队列先前为空时才会发出消息通知。如果在调用mq_notify()时队列不为空,则只有在队列清空并且有新消息到达后才会发出通知。
2)通知发生一次:在发送通知后,通知注册被删除,另一个进程可以注册消息通知。如果通知的进程希望接收下一个通知,则可以使用mq_notify()来请求进一步的通知。
3)只能注册一个进程来接收来自消息队列的通知。
所以:
1)在使用mq_notify()注册后,立即清空MsgQ以在阅读器进程中重新发送新消息。
2)在通知功能中重新注册以接收下一条消息。
3)仅注册1个从Q接收消息的过程。
以下是C ++中的简单消息队列读取器代码:
#include <iostream>
#include <mqueue.h>
#include <string.h>
#include <sstream>
#include <unistd.h>
#include <errno.h>
using namespace std;
#define MSG_Q_NAME "/MY_MSGQ_3"
static void /* Thread start function */
tfunc(union sigval sv)
{
mqd_t msq_id = *(static_cast<mqd_t*>(sv.sival_ptr));
struct mq_attr attr;
if(mq_getattr(msq_id, &attr) < 0)
{
cout << "Error in mq_getattr " << strerror(errno) << endl;
return;
}
// Reregister for new messages on Q
struct sigevent sev;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = tfunc;
sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_ptr = sv.sival_ptr;
if (mq_notify(msq_id, &sev) < 0)
{
cout << "Error during Reregister in msq_notify : "
<< strerror(errno) << endl;
exit(EXIT_FAILURE);
}
// Read new message on the Q
char* arr = new char[attr.mq_msgsize];
memset(arr, 0, attr.mq_msgsize);
if(mq_receive(msq_id, arr, attr.mq_msgsize, 0) < 0)
{
if(errno != EAGAIN)
{
cout << "Error in mq_receive " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
}
else
{
cout << "Msg rcvd " << arr << endl;
}
}
int main()
{
mqd_t msq_id = mq_open(MSG_Q_NAME, O_RDONLY | O_NONBLOCK | O_CREAT, 0666, 0);
if(msq_id == (mqd_t) -1)
{
cout << "Error on msg Q creation: " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
// The process is registered for notification for new message on the Q
struct sigevent sev;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = tfunc;
sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_ptr = &msq_id;
if (mq_notify(msq_id, &sev) < 0)
{
cout << "Error on msg Q notify : " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
else
{
cout << "Notify for msg Q reception " << MSG_Q_NAME << endl;
}
// Man Page mq_notify: Message notification occurs only when a new
// message arrives and the queue was previously empty. If the queue was
// not empty at the time mq_notify() was called, then a notification will
// occur only after the queue is emptied and a new message arrives.
//
// So emptying the Q to recv new messages
ssize_t n = 0;
struct mq_attr attr;
if(mq_getattr(msq_id, &attr) < 0)
{
cout << "Error in mq_getattr " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
char* arr = new char[attr.mq_msgsize];
memset(arr, 0, attr.mq_msgsize);
while((n = mq_receive(msq_id, arr, attr.mq_msgsize, 0) >= 0))
{
cout << "Empty the Q. Msg rcvd " << arr << endl;
}
while(1)
;
mq_close(msq_id);
}
这是一个简单的消息Q writer代码:
#include <iostream>
#include <mqueue.h>
#include <string.h>
#include <sstream>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
using namespace std;
#define MSG_Q_NAME "/MY_MSGQ_3"
int main()
{
struct mq_attr attr;
memset(&attr, 0, sizeof attr);
attr.mq_msgsize = 8192;
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
mqd_t msq_id = mq_open(MSG_Q_NAME, O_RDWR | O_CREAT | O_NONBLOCK,
0777, &attr);
if(msq_id == (mqd_t) -1)
{
cout << "Error on msg Q creation: " << strerror(errno) << endl;
exit(1);
}
// Write 5 msgs on message Q
for(int i = 0; i < 5; ++i)
{
stringstream s;
s << "My Msg " << i;
if(mq_send(msq_id, s.str().c_str(), strlen(s.str().c_str()), 0) < 0)
{
if(errno != EAGAIN)
{
cout << "Error on sending msg on MsgQ " << strerror(errno);
mq_close(msq_id);
exit(1);
}
}
else
{
cout << "Sent msg " << s.str() << endl;
}
sleep(1); // Easily see the received message in reader
}
mq_close(msq_id);
}