C NIF调用Erlang后二进制值的更改
我打算使用NIFs为我计划在Erlang中编写的应用程序操作二进制文件。 下面给出了NIF的cpp文件和erl文件的主要链接 [Erl要点链接] [C++要点链接] 基本上我在做一个简单的测试。跨NIF调用共享二进制文件,并通过连续的NIF调用成功地操作它们 如果您在erlang REPL中测试代码C NIF调用Erlang后二进制值的更改,c,c++11,erlang,erlang-shell,erlang-nif,C,C++11,Erlang,Erlang Shell,Erlang Nif,我打算使用NIFs为我计划在Erlang中编写的应用程序操作二进制文件。 下面给出了NIF的cpp文件和erl文件的主要链接 [Erl要点链接] [C++要点链接] 基本上我在做一个简单的测试。跨NIF调用共享二进制文件,并通过连续的NIF调用成功地操作它们 如果您在erlang REPL中测试代码 c(binary_test). Ref=binary_test:open(<<1>>). binary_test:increment(Ref,<<3>>
c(binary_test).
Ref=binary_test:open(<<1>>).
binary_test:increment(Ref,<<3>>).
在我的Mac电脑上
我还想问一下在NIF中操作共享资源的并发进程。这是可能的,还是有一条规则规定NIF必须在单个Erlang进程中访问。
ERL\u NIF\u TERM
s必须与ErlNifEnv
关联,并且传递给NIF函数的env仅在该函数调用期间有效。当您将一个术语存储到BinaryStore
对象中,然后从另一个nif调用中使用它时,您就违反了这个规则。您的选择:
您遇到问题是因为您非法访问内存。在
BinaryStore
构造函数中,您试图从传递给binary\u test:open/1
的参数列表中保存二进制文件,但这不起作用,因为一旦NIF调用完成,这些参数就会被释放。您需要保存参数的副本,以便以后使用。为此,首先向BinaryStore
类添加一个新成员:
ErlNifEnv* term_env;
接下来,修改构造函数以分配术语\u env
,然后使用它复制传入术语:
BinaryStore(ERL_NIF_TERM binary)
{
term_env = enif_alloc_env();
binary_term = enif_make_copy(term_env, binary);
}
这将在term\u env
环境中分配binary\u term
,然后将传入的术语复制到其中。您还需要一个析构函数来释放term\u env
:
~BinaryStore()
{
enif_free_env(term_env);
}
最后,在increment\u binary
函数中检查binary\u term
时,需要传递term\u env
而不是env
:
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>>
1>Ref=binary\u测试:open()。
读取共享库的符号。完成
2> 二进制测试:增量(参考,)。
1.
3.
1.
1.
(顺便说一下,从Erlang emulator内部打印时,您应该使用“\r\n”
行结尾,而不仅仅是“\n”
,以便换行符始终返回到最左边的列。)
您还有一个问题,那就是您泄漏了为new\u bin2
分配的内存
关于学习NIFs的详细信息,我的建议是首先避免使用像
nifpp
这样的包,这样您就可以了解和了解有关内存所有权、资源分配和释放以及参数转换的所有详细信息。一旦你理解了它们,使用像nifpp
这样的软件包就会变得更简单、更有效。什么是“二进制”?你是说“一个整数”吗?二进制是一种本机Erlang类型,可以包含任何类型。例如,,。从本质上讲,您可以将其视为ByteString类型的东西。NIF和资源可能同时被多个进程使用,但线程安全的责任在您身上。谢谢。明白了,谢谢你的解释。使用nifpp
的原因基本上是为了编写简洁的代码,nifpp
我认为,一旦没有任何指向资源的引用,就会释放分配给new_bin2
的内存,我认为资源在分配后会被破坏,如果通过C
Api调用,它应该被破坏。如果我错了,请纠正我。但对于new\u bin2
,您只需通过enif\u alloc\u binary
为其分配内存,然后使用memcpy
将内存复制到其中。没有涉及它的nifpp
调用。因此,在退出increment\u binary
函数之前,需要对其调用enif\u release\u binary
。或者,完全摆脱new\u bin2
,只需使用ibin
代替它,因为不需要复制ibin
来使用它的值。谢谢,我明白你的意思。关于ibin
,我想我只能访问ibin
值,不能修改它。正确,您不能更改ibin
。但是用它来代替new\u bin2
是非常好的,因为1)new\u bin2
只是ibin
的一个副本,2)您使用new\u bin2
只是为了读取,而不是写入。
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>>