2013-06-02 21 views
1

我想知道如何在C中集成Ruby的事件循環和Ruby擴展。我不確定這是否是正在嘗試做的事情的正確方法,所以我會解釋這個問題。將Ruby中的事件循環集成到C擴展中

我使用msgrcvmsgsnd(IPC),因此在Ruby C擴展和其他應用程序之間發送消息。問題是接收消息的擴展方法會產生如下的無限循環:

do{ 
    if(msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0){ 
     printf("Error"); 
    }else{ 
     rb_funcall(self, rb_intern("callback_method"), 1, rb_str_new2(rcvbuffer.mtext)); 
    } 
} while(strcmp(rcvbuffer.mtext, "exit") != 0); 

並且鎖定了ruby的解釋器。我希望能夠在不阻塞的情況下在Ruby擴展中調用接收方法。

這怎麼辦?

+0

msgrcv和msgsnd從哪裏來?他們有沒有選擇只檢查幾毫秒,然後繼續?這會給你三個條件 - 錯誤,過程消息和「繼續」 - 用一個「繼續」你退出循環,並確保它將被控制代碼再次調用,或者有相反的情況,並且沒有消息回調「這是重複調用,而沒有發生任何事情。如果由於某種原因兩者都不可行,那麼在單獨的線程中運行消息處理可能會有效,但會讓人頭疼,尤其是在您已經運行異步進程的情況下。 –

+0

@NeilSlater msgrcv和msgsnd是標準內核調用http://linux.die.net/man/2/msgrcv我想避免線程。 – alexandernst

+0

我想你想設置IPC_NOWAIT標誌,當沒有要處理的消息時,通過將控制交給主腳本來處理錯誤num(例如,將錯誤num賦給一個變量並檢查它現在只有'printf' ( 「錯誤」)')。這可以是「無消息」回調 - 類似於處理消息的消息 - 也可以返回形式的擴展,期望主代碼在準備處理消息時再次調用。你想要的取決於包含代碼的結構。 –

回答

2

沒測試過,這是假定你要調用的類中的一些方法(這顯然需要實現)時,有沒有消息:

do{ 
    if(msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, IPC_NOWAIT) < 0) { 
     // Handle error conditions 
     if (rcvbuffer.errno == ENOMSG) { 
      rb_funcall(self, rb_intern("no_msg_callback_method"), 0); 
      // Or you could simply . . . 
      // break; 
     } else { 
      printf("Error"); 
     } 
    }else{ 
     rb_funcall(self, rb_intern("callback_method"), 1, rb_str_new2(rcvbuffer.mtext)); 
    } 
} while(strcmp(rcvbuffer.mtext, "exit") != 0); 

你的另一種選擇是設置一個標誌,並允許當沒有消息時退出循環。然後方法調用者需要確定它是否收到了「退出」消息(該消息也發送到callback_method),或者沒有消息要當前處理,因此可以執行其他操作。

+0

謝謝,但仍然有一個主要問題。消息一直到達(大約50/s),所以循環不會退出。我需要一種方式來以非阻塞的方式從Ruby的C擴展中調用該代碼塊。像MyModule :: start_receiving_msgs()\ n放置「收到消息!」 <----所以我真的開始接收消息並看到投入。編輯:哦,我真的想避免線程。 – alexandernst

+0

在這種情況下,不要使用無限的'while循環 - 使用'for'循環甚至根本沒有循環。循環在那裏假設你的代碼的主要目的是處理消息。我擔心你期望它處理的流量意味着消息會很快備份,所以它不能做很多其他事情 - 例如,假設您的消息處理需要5ms,那麼只需15ms的處理時間(平均而言)即可完成腳本在處理消息之間應做的任何操作。 –

+0

我需要一個循環,在擴展名或我的紅寶石代碼中,以接收所有消息。問題是,如果我把它放在擴展中,我會阻塞腳本的其餘部分,如果我把它放在ruby腳本中,我什麼也做不了(或者我可以嗎?)。我不確定是否可以創建類似以下內容的內容:10毫秒的循環,50毫秒的下一循環,執行任務,調用預定循環。類似於Javascript中的警報。那可能嗎? – alexandernst