Mq_notify in Cygwin not starting

I use POSIX queues (mqueue) to communicate between threads.

The problem is that mq_notify does not work properly in my unit tests on Cygwin. It never starts, even if the msg queue goes from empty to 1 msg.

I made an example that works on Linux. When the same code compiles in Cygwin, it does not work.

Maybe Cygwin does not 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("%sq:%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
source share
2 answers

I do not have Cygwin, so I could not confirm what you see. However, this error jumps out: in handleMessage() you reset notify and use this line:

 sev.sigev_value.sival_ptr = &mqdes; 

This will not work because mqdes is the current stack variable. Once the queue is empty, this thread (and its associated stack) will disappear. When this happens, mqdes may indicate something in memory when the next thread starts. A simple fix is ​​to simply use the pointer passed to the current thread.

 sev.sigev_value.sival_ptr = sv.sival_ptr; 

In your main question, are you sure to delete the queue before performing subsequent runs in the program? If the queue is not empty, the new thread will never start.

+1
source

As pointed out by @Duck, your lineup is probably not empty. This was my case when I encountered a similar problem today. You must empty the queue with several calls to mq_receive in order to be notified in the future. In main() , I suggest the following code after 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); } } 
0
source

Source: https://habr.com/ru/post/1445790/


All Articles