2013-06-02 84 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