mq_notify не уведомляет о событии (программирование в Linux) - PullRequest
0 голосов
/ 01 декабря 2010

Я использую 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 голосов
/ 17 апреля 2013

Также проверьте, есть ли в очереди сообщения.Если в очереди существуют сообщения, то mq_notify () не получит уведомление, пока очередь не станет пустой, а затем не появятся новые сообщения. Поскольку очередь является постоянной для всех прогонов программы, необходимо убедиться, что mq_unlink () уже вызвана в очередиперед открытием.

0 голосов
/ 11 августа 2017

Man Page mq_notify :

1) Уведомление о сообщении происходит только тогда, когда приходит новое сообщение и очередь ранее была пуста.Если очередь не была пуста во время вызова mq_notify (), то уведомление будет появляться только после того, как очередь очищена и появится новое сообщение.

2) Уведомление происходит один раз: после доставки уведомления регистрация уведомления удаляется, и другой процесс может зарегистрироваться для уведомления о сообщении.Если уведомленный процесс желает получить следующее уведомление, он может использовать mq_notify () для запроса дополнительного уведомления.

3) Для получения уведомления из очереди сообщений может быть зарегистрирован только один процесс.

Итак:

1) Очистить MsgQ для немедленного получения новых сообщений в процессе чтенияпосле регистрации в mq_notify ().

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:

#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);
}
0 голосов
/ 30 декабря 2010

Поскольку код является копией со страницы руководства, я бы спросил:

  1. Вы уверены, что правильно отправляете сообщение в очередь?
  2. Попробуйте сначала прочитать с помощью блокирующего чтения и посмотретьвы что-то получаете.

В Linux вы можете использовать select / poll / epoll для ожидания уведомлений об очереди, а mqd_t - обычный файловый дескриптор.

...