2013-10-28 83 views
2

如何使用ev_io與mqueue?我試圖做到以下幾點,但沒有運氣。如何使用Libev io與mqueue

#include <fcntl.h> 
#include <sys/stat.h> 
#include <mqueue.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include "ev.h" 

#define MAX_Q_SIZE 255 
#define MY_QUEUE "/test_queue" 

typedef struct __test_ctxt_t 
{ 
    ev_timer timeout_watcher[32]; 
    ev_io  stdin_watcher; 
    struct ev_loop *loop; 
    mqd_t  mq; 
    int   data; 
}test_ctxt_t; 

static test_ctxt_t *g_ctxt = NULL; 

static void mq_callback(EV_P_ struct ev_io *w, int revents) 
{ 
    test_ctxt_t *ctxt = (test_ctxt_t *)w; 
    struct  mq_attr attr; 
    char  msg[256]; 
    int   rcvd_msg_size; 

    rcvd_msg_size = mq_receive(ctxt->mq, msg, MAX_Q_SIZE, NULL); 
    if (rcvd_msg_size >= 0) 
    { 
     msg[rcvd_msg_size] = '\0'; 
     printf("Received: %s\n", msg); 
     if (strcmp(msg, "stop") == 0) 
     { 
      printf("Exiting....\n"); 
      ev_unloop (EV_A_ EVUNLOOP_ONE); 
     } 
    } 
} 

static void timeout_cb1 (EV_P_ struct ev_timer *w, int revents) 
{ 
    puts ("timeout timeout_cb1"); 
    //ev_unloop (EV_A_ EVUNLOOP_ONE); 
} 

static void timeout_cb2 (EV_P_ struct ev_timer *w, int revents) 
{ 
    puts ("timeout timeout_cb2"); 
    //ev_unloop (EV_A_ EVUNLOOP_ONE); 
} 
static void timeout_cb3 (EV_P_ struct ev_timer *w, int revents) 
{ 
    puts ("timeout timeout_cb3"); 
    //ev_unloop (EV_A_ EVUNLOOP_ONE); 
} 

int main (void) 
{ 
    struct  mq_attr attr; 

    g_ctxt = (test_ctxt_t *)calloc(1, sizeof(test_ctxt_t)); 

    g_ctxt->loop = ev_default_loop (0); 

    /* initialize the queue attributes */ 
    attr.mq_flags = 0; 
    attr.mq_maxmsg = 10; 
    attr.mq_msgsize = 255; 
    g_ctxt->mq = mq_open(MY_QUEUE, O_CREAT | O_RDONLY, 0644, &attr); 
    if (g_ctxt->mq == -1) 
    { 
     printf("Unable to open Queue"); 
     return -1; 
    } 

    ev_io_init(&g_ctxt->stdin_watcher, mq_callback, g_ctxt->mq, EV_READ); 
    ev_io_start(g_ctxt->loop, &g_ctxt->stdin_watcher); 

    ev_timer_init (&g_ctxt->timeout_watcher[0], timeout_cb1, 10, 0.); 
    ev_timer_start (g_ctxt->loop, &g_ctxt->timeout_watcher[0]); 

    ev_loop (g_ctxt->loop, 0); 

    return 0; 
} 

我可以得到定時器回調,但io回調從不會被調用發送到隊列中的消息。是否有可能與libev一起使用POSIX mqueue?

+0

我不明白爲什麼這不會在Linux上工作,但我沒有耐心安裝ev_io來測試它。看起來lib只是將'select'或'poll'包裝起來,兩者都與linux中的mqd_t(只是文件desc)一起工作。 OP,你在什麼操作系統上? – Duck

+1

這裏:http://stackoverflow.com/questions/10045015/why-is-there-no-poll-select-like-mechanism-for-message-queue它指定在Linux上select/poll可以和mqs一起使用。但它不是便攜式的。 –

+0

同意@ O.C。 Linux消息隊列是文件描述符,因此它們可以在libev IO觀察器中使用。這不幸是不可移植的方法。 –

回答

0

基本上有三種方式,如何做到這一點:

1)在Linux平臺上,消息隊列處理程序是有效的文件描述符。

輪詢消息隊列描述符

在Linux中,消息隊列描述符實際上是一個文件描述符, 並且可以使用選擇(2),輪詢(2),或epoll的被監測(7)。這是 不便攜式。

mq_overview手冊頁

您可以利用ev_io觀察家聽傳入的消息。

這是LINUX特定和不可移植的代碼。

2)您可以使用功能mq_notify配置一個信號,該信號在消息隊列接收到新消息時發送。這個信號可以由來自libev的ev_signal觀察者處理。

這似乎是更便攜的代碼,但由於信號交互,性能會低一點。

請參閱mq_notify手冊頁。

3)切換到面向數據報的套接字UNIXnetwork。這些提供了大致相同的發送消息(又名數據報)的能力。您將獲得無連接,盡力而爲的交付,不可靠的消息傳遞服務。

這種方法非常便攜。

Macintosh注意事項:
在macOS中沒有POSIX消息隊列實現,因此這種代碼的可移植性對於此Apple平臺而言是有限的。有可能模仿NSOperationQueue或Grand Central Dispatch的相同功能,但它肯定會導致大量的工作。