NIF调用Erlang后二进制更改的值

时间:2014-10-22 10:58:32

标签: c c++11 erlang erlang-shell erlang-nif

我打算使用NIF操作二进制文件用于我计划在Erlang中编码的应用程序。 下面给出了cpp文件的gist链接和NIF的erl文件。

[Erl Gist Link] https://gist.github.com/abhijitiitr/3a5bc97184d6dd32f97b

[C ++ Gist Link] https://gist.github.com/abhijitiitr/24d2b780f2cdacebfb07

基本上我试图做一个简单的测试。在NIF调用之间共享二进制文件,并使用连续的NIF调用成功操作它们。

如果您通过

测试erlang REPL中的代码
c(binary_test).
Ref=binary_test:open(<<1>>).
binary_test:increment(Ref,<<3>>).

存储的二进制文件在NIF调用之间发生变化。第三个命令的REPL输出是

1
 3
  60
    60
      <<"?">>

我在初始化阶段通过<<1>>。为什么会改为<<60>>?我无法弄清楚这里发生了什么。有人可以指出错误吗?

C ++编译指令

clang++ -std=c++11 -stdlib=libc++ -undefined dynamic_lookup -O3 -dynamiclib binary_test.cpp -o binary_test.so -I /usr/local/Cellar/erlang/17.0/lib/erlang/erts-6.0/include/ 

在我的Mac上。

此外,我想问一下在NIF中操作共享资源的并发进程。这是可能的还是有一个规则,即必须在单个Erlang进程中访问NIF。

2 个答案:

答案 0 :(得分:5)

您遇到问题是因为您非法访问内存。在BinaryStore构造函数中,您试图从传递给binary_test:open/1的参数列表中保存二进制文件,但这不起作用,因为一旦NIF调用完成后,这些参数就会被释放。您需要保存参数的副本以便以后使用它。为此,请先向BinaryStore班级添加新成员:

    ErlNifEnv* term_env;

接下来,修改构造函数以分配term_env,然后使用它来复制传入的术语:

    BinaryStore(ERL_NIF_TERM binary)
    {
        term_env = enif_alloc_env();
        binary_term = enif_make_copy(term_env, binary);
    }

这会在binary_term环境中分配term_env,然后将传入的术语复制到其中。您还需要一个析构函数来释放term_env

    ~BinaryStore()
    {
        enif_free_env(term_env);
    }

最后,在检查term_env函数中的env时,您需要传递binary_term而不是increment_binary

    nifpp::get_throws(term_env, binary_term, ibin);

通过这些修改,我得到了以下运行代码的结果:

1> Ref=binary_test:open(<<1>>).
Reading symbols for shared libraries . done
<<>>
2> binary_test:increment(Ref,<<3>>).
1
 3
  1
   1
    <<4>>

(顺便说一句,从Erlang模拟器内部打印时,您应该使用"\r\n"行结尾而不仅仅是"\n",以便新行始终返回到最左侧的列。)

您仍有一个问题,即您泄漏了为new_bin2分配的内存。

我对学习NIF详细信息的建议是首先避免使用nifpp之类的包,这样您就可以了解NIF API以及有关内存所有权,资源分配和释放以及参数的所有详细信息转换。一旦理解了它们,使用像nifpp这样的软件包就会变得更加容易和富有成效。

答案 1 :(得分:2)

ERL_NIF_TERM必须与ErlNifEnv相关联,并且传递给nif函数的env仅在该函数调用期间有效。将术语存储到BinaryStore对象中,然后在另一个nif调用中使用它时,您违反了此规则。你的选择:

  1. 为您的二进制商店创建一个新的ErlNifEnv,并将nif调用中的术语复制到这个新的环境中。

  2. 使用C ++数据结构(例如std::vector<unsigned char>)来存储二进制数据。我认为这对你的情况会更简单。