2012-11-13 41 views
4

我正在使用POSIX隊列(mqueue)在線程之間進行通信。Cygwin中的mq_notify不會觸發

我遇到的問題是,在Cygwin的單元測試中,mq_notify無法正常工作。即使msg隊列從空到1 msg,它也不會觸發。

我做了一個在Linux上運行的例子。當在Cygwin中編譯相同的代碼時,它不起作用。

是不是Cygwin不支持mq_notify或者它是Cygwin中的錯誤?

通知例如:

#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; 
} 
+0

得到了類似的問題與示例代碼從[http://man7.org/tlpi/code/online/index.html](TLPI)。你找到了出路嗎? @Duck TLPI中的示例代碼正確使用sv.sival_ptr重新註冊通知。所以根源在別處。 –

回答

1

我沒有Cygwin的設置,所以我無法證實你所看到的。然而這個錯誤跳出:在handleMessage()重置通知,並使用這行:

sev.sigev_value.sival_ptr = &mqdes; 

這是行不通的,因爲符mqdes是當前堆棧上的變量。一旦隊列爲空,此線程(及其關聯的堆棧)即將消失。發生這種情況時,當下一個線程啓動時,mqdes可以指向內存中的任何內容。一個簡單的解決方法是隻使用傳入當前線程的指針。

sev.sigev_value.sival_ptr = sv.sival_ptr; 

在你的主要問題上,你確定你在程序中進行後續運行之前刪除隊列嗎?如果隊列不是空的,新線程將永遠不會啓動。

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); 
    } 
}