4

スレッド間の通信にPOSIXキュー(mqueue)を使用しています。

私が抱えている問題は、Cygwinでの単体テストでmq_notifyが期待どおりに機能しないことです。msgキューが空から1msgになっても、トリガーされることはありません。

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; 
}
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 に答える