mq_notify没有通知事件(Linux编程)

时间:2010-12-01 08:09:33

标签: c linux posix ipc message-queue

我正在使用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);    
}

3 个答案:

答案 0 :(得分:0)

因为代码是手册页的副本,我会问:

  1. 您确定要将邮件正确发送到队列吗?
  2. 首先尝试使用阻止读取来查看是否有所收获。
  3. 在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);
}