【问题标题】:How can a Ruby C extension store a proc for later execution?Ruby C 扩展如何存储 proc 以供以后执行?
【发布时间】:2018-09-26 21:00:33
【问题描述】:

目标:允许 c 扩展接收块/过程以延迟执行,同时保留当前执行上下文。

我有一个接受callback(通过VALUE hash 参数)或block 的c 方法(暴露于ruby)。

// For brevity, lets assume m_CBYO is setup to make a CBYO module available to ruby
extern VALUE m_CBYO;
VALUE CBYO_add_callback(VALUE callback)
{
    if (rb_block_given_p()) {
        callback = rb_block_proc();
    }

    if (NIL_P(callback)) {
        rb_raise(rb_eArgError, "either a block or callback proc is required");
    }

    // method is called here to add the callback proc to rb_callbacks
}
rb_define_module_function(m_CBYO, "add_callback", CBYO_add_callback, 1);

我有一个结构用来存储这些数据和一些额外的数据:

struct rb_callback
{
    VALUE rb_cb;
    unsigned long long lastcall;
    struct rb_callback *next;
};
static struct rb_callback *rb_callbacks = NULL;

到时候(由 epoll 触发),我遍历回调并执行每个回调:

rb_funcall(cb->rb_cb, rb_intern("call"), 0);

当这种情况发生时,我看到它成功地执行了回调中的 ruby​​ 代码,但是,它正在转义当前的执行上下文。

例子:

# From ruby including the above extension
CBYO.add_callback do
    puts "Hey now."
end

loop do
    puts "Waiting for signal..."
    sleep 1
end

当收到信号时(通过 epoll),我将看到以下内容:

$> Waiting for signal...
$> Waiting for signal...
$> Hey now.
$> // process hangs
$> // Another signal occurs
$> [BUG] vm_call_cfunc - cfp consistency error

有时,在错误再次出现之前,我可以处理多个信号。

【问题讨论】:

    标签: c ruby ruby-c-extension


    【解决方案1】:

    我在调查a similar issue时找到了答案。

    事实证明,我也在尝试使用 MRI 不支持的本机线程信号(pthread_create)。

    TLDR; Ruby VM 当前(在撰写本文时)不是线程安全的。查看 this nice write-up on Ruby Threading 以更好地全面了解如何在这些范围内工作。

    您可以使用 Ruby 的 native_thread_create(rb_thread_t *th),它将在幕后使用 pthread_create。您可以在方法定义上方的文档中了解一些缺点。然后,您可以使用 Ruby 的 rb_thread_call_with_gvl 方法运行回调。另外,我还没有在这里做过,但是创建一个包装方法可能是个好主意,这样您就可以使用rb_protect 来处理回调可能引发的异常(否则它们将被 VM 吞噬)。

    VALUE execute_callback(VALUE callback)
    {
        return rb_funcall(callback, rb_intern("call"), 0);
    }
    
    // execute the callback when the thread receives signal
    rb_thread_call_with_gvl(execute_callback, data->callback);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      • 2017-11-28
      • 2014-07-08
      相关资源
      最近更新 更多