4

I'm using POSIX queues (mqueue) to communicate between threads.

The problem I have is that mq_notify doesn't function as expected in my unit tests on Cygwin. It never triggers even though the msg queue goes from empty to 1 msg.

I made an example that functions on Linux. When the same code is compiled in Cygwin, it doesn't work.

Could it be that Cygwin doesn't support mq_notify or is it a bug in Cygwin?

notification example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "mqueue.h"

static void error(const char *msg)
{
    perror(msg);
    exit(1);
}

static void handleMessage(union sigval sv)
{
    ssize_t n;
    char buf[256];
    struct mq_attr mqAttr = {0};
    mqd_t mqdes = *((mqd_t *) sv.sival_ptr);

    printf("handleMessage\n");
    if (mq_getattr(mqdes, &mqAttr) == -1) {
        error("mq_getattr");
    }

    printf("handleMessage msgs:%i\n", mqAttr.mq_curmsgs);

    while (mqAttr.mq_curmsgs > 0) {
        n = mq_receive(mqdes, buf, mqAttr.mq_msgsize, NULL);

        if (n == -1) {
            error("mq_receive");
            break;

        } else {
            printf("Read %ld bytes from MQ\n", (long) n);
        }

        if (mq_getattr(mqdes, &mqAttr) == -1) {
            error("mq_getattr");
        }
    }

    {
        struct sigevent sev;
        sev.sigev_notify = SIGEV_THREAD;
        sev.sigev_notify_function = handleMessage;
        sev.sigev_notify_attributes = NULL;
        sev.sigev_value.sival_ptr = &mqdes; 

        if (mq_notify(mqdes, &sev) == -1) {
           error("mq_notify");
        }
    }
}

int main(int argc, char *argv[])
{       
    struct mq_attr      mqAttr;
    mqd_t queue;
    struct sigevent sev;

    mqAttr.mq_maxmsg = 10;
    mqAttr.mq_msgsize = 50;
    mqAttr.mq_flags = 0;

    queue = mq_open(argv[1], O_CREAT | O_RDWR, 0666, NULL);

    if(queue == -1) {
        error("mq_open");
    }
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = handleMessage;
    sev.sigev_notify_attributes = NULL;
    sev.sigev_value.sival_ptr = &queue;  

    if (mq_notify(queue, &sev) == -1) {
       error("mq_notify");
    }

    while(1) {
    /* Pass data to mq */
        char buffer[20];
        static int cnt = 0;

        sprintf(buffer, "mq_send %i", ++cnt);
        printf("%s q:%X\n", buffer, queue);
        if (mq_send(queue, (char*)buffer, (strlen(buffer) + 1), 100) != 0) {
            error("mq_send");
        }
        usleep(1000000); // sleep 1s
    }

    return 0; 
}
4

2 回答 2

1

我没有设置 Cygwin,所以我无法确认您所看到的内容。但是,此错误会跳出:在handleMessage()您重置通知并使用此行时:

sev.sigev_value.sival_ptr = &mqdes;

这是行不通的,因为 mqdes 是当前堆栈上的一个变量。一旦队列为空,该线程(及其关联的堆栈)将消失。当这种情况发生时,当下一个线程启动时,mqdes 可以指向内存中的任何内容。一个简单的解决方法是只使用传递给当前线程的指针。

sev.sigev_value.sival_ptr = sv.sival_ptr;

关于您的主要问题,您确定在程序中进行后续运行之前删除队列吗?如果队列不为空,则永远不会启动新线程。

于 2012-11-13T22:35:52.027 回答
0

正如@Duck 所说,您的队列可能不是空的。这就是我今天遇到类似问题时的情况。您需要通过多次调用清空队列mq_receive才能在将来获得通知。在您的main()中,我建议在您之后使用以下代码mq_notify

mqd_t queue_nb; /* non-blocking queue */

[...]

if (mq_notify(queue, &sev) == -1) {
   error("mq_notify");
}

queue_nb = mq_open(argv[1], O_NONBLOCK | O_RDONLY, 0666, NULL);
if(queue == -1) {
    error("mq_open");
}

if (mq_getattr(mqdes, &mqAttr) == -1) {
    error("mq_getattr");
}

n = 0;
while (n >= 0) {

    /* will not block */
    n = mq_receive(queue_nb, buf, mqAttr.mq_msgsize, NULL);
    if (n > 0) {
        printf("Read %ld bytes from MQ\n", (long) n);
    }
}
于 2013-08-20T21:00:02.063 回答