0

编辑:这是对问题的重写,因为它以前是如此不具体。

所以我在解决 C 扩展中跨实例共享变量的问题时遇到了问题。这是我遇到的一个例子。

>> t = SCOPE::TestClass.new #=> #<SCOPE::TestClass:0x000001011e86e0>
>> t.set = 4 #=> 4
>> t.get #=> 4
>> v = SCOPE::TestClass.new #=> #<SCOPE::TestClass:0x00000101412bf0>
>> v.set = 5 #=> 5
>> v.get #=> 5
>> t.get #=> 5

下面代码中的最佳解决方案是简单地使用您可以设置的 ruby​​ 变量吗?

void rb_define_variable(const char *name, VALUE *var)

或者在 C 中是否有我没有看到或理解的解决方案?

代码:

#include <stdlib.h>
#include <ruby.h>

VALUE TestClass;
VALUE SCOPE;
VALUE test_var;

VALUE set(self, val);
VALUE get();

VALUE set(VALUE self, VALUE val) {
    test_var = NUM2INT(val);
    return Qnil;
}

VALUE get() {
    return INT2NUM(test_var);
}

void Init_scope() 
{
    SCOPE = rb_define_module("SCOPE");
    TestClass = rb_define_class_under(SCOPE, "TestClass", rb_cObject);

    rb_define_method(TestClass, "set=", set, 1);
    rb_define_method(TestClass, "get", get, 0);
}
4

2 回答 2

1

好的,现在我想我看到了问题所在。您的

  VALUE test_var;

是测试类的每个实例之间的一种“共享”值。这当然是一个错误,因为它在创建新实例或调用方法集时被覆盖。因此,您可以只拥有一个实例,并在每个实例之间共享一个值。

当然你做错了:ruby 必须提供上下文和检索它的方法,可能 get 函数的原型必须至少有 VALUE self 作为参数,如 set。该值不能存储到全局或静态局部变量中:它必须以某种方式存储到对象的“上下文”中。为了知道怎么做,我需要一个关于 ruby​​ ext 的快速教程。同时尝试在这里更深入地阅读。

特别是,将注意力集中在“访问变量”以及如何定义实例变量上。

我已经这样做了,这似乎有效;你可能想努力实现你的扩展目的(我已经重命名了一些东西,并修复了其他东西;我还删除了 INT2NUM 和 NUM2INT 的东西,你可以根据需要放回去)

#include <stdlib.h>
#include <ruby.h>

VALUE TestClass;
VALUE SCOPE;

VALUE set(VALUE, VALUE);
VALUE get(VALUE);

VALUE set(VALUE self, VALUE val) {
    (void)rb_iv_set(self, "@val", val);
    return Qnil;
}

VALUE get(VALUE self) {
  return rb_iv_get(self, "@val");
}

void Init_RubyTest() 
{
    SCOPE = rb_define_module("RubyTest");
    TestClass = rb_define_class_under(SCOPE, "TestClass", rb_cObject);

    rb_define_method(TestClass, "set=", set, 1);
    rb_define_method(TestClass, "get", get, 0);
}

如果我们不知道“C 扩展”(我想是 Ruby 的?)是如何工作的,这个问题就无法完全回答,而且我真的不知道。

声明为静态的“全局”变量对于定义它的文件是本地的,不能从外部访问,即它在该文件内是全局的,但它不是所有链接文件的全局变量。

func1 确实可以访问 bar;它不能仅仅因为符号在声明之前是未知的(出于同样的原因 func1 不能调用 func2,或者至少编译器对丢失的原型给出警告,那么无论如何都会找到 func2 的代码),但无论如何,一旦知道符号,就可以访问它。相反,这些变量 bar 和 foo 不能从外部看到(因此不是全局的),因为符号 foo 和 bar 是不可见的。

如果此代码应该编译为共享对象或静态库,链接共享对象/静态库的代码将看不到 foo 和 bar。

于 2011-06-26T18:21:54.967 回答
1

全局变量根据彼此共享的 ruby​​ c 扩展规范(参见文档)。将变量范围限制在最不可见的范围内是最好的选择。如果您碰巧有一个共享变量,那么它至少对同步问题应该是安全的。

于 2011-06-26T18:10:43.253 回答