1

我创建了一个模块,它以完全不同的方式透明地处理某些文件,作为 Erlangfile:open/2和它返回的 IoDevice/文件描述符的替代品。在许多情况下,它只是简单地返回 Erlang 的结果file:open/2,而在其他情况下,它返回一个通过 HTTP API(CloudFiles 或 AWS S3)读写的自定义 IoDevice。

最近这是一个普通的模块,但我一直在尝试将其转换gen_server为更好地处理异步 HTTP 调用(以及其他原因)。这些自定义位运行良好,但我无法简单地file:open/2从 a调用gen_server:handle_call/3并返回生成的 IoDevice。问题是在我gen_server打开文件以使用 IoDevice 回复后,gen_server:handle_info/2我的gen_server.

...
handle_call({open, Path, Flags}, _From, State) ->
    Reply = case handle_external_file(Path) of
                false -> file:open(Path, Flags);
                true -> external_file:open(Path)
            end,
    %%
    %% Reply is {ok,{file_descriptor,prim_file,{#Port<0.1896>,14}}}
    %%
    {reply, Reply, State};
...
handle_info(Message, State) ->
    %%
    %% Message is {#Port<0.1896>,{data,[3,0,0,0,0,0,0,0,0]}}
    %%
    io:format("UNEXPECTED MESSAGE: ~p~n", [Message]),
    {noreply, State}
...

我认为这与文档中的以下内容有关:

IoDevice 实际上是处理文件的进程的 pid。此进程链接到最初打开文件的进程。如果与 IoDevice 链接的任何进程终止,则文件将被关闭并且进程本身将被终止。从此调用返回的 IoDevice 可用作 IO 函数的参数(请参阅 io(3))。

有没有办法从 a 打开文件gen_server,将其 IoDevice 交给另一个进程?

4

1 回答 1

1

问题不在于文件:打开问题在于在 external_file:open(Path) 中打开的端口驱动程序。IoDevice 可以被任何进程使用,但只有在创建进程存在之前它才可用。而创建端口驱动程序的进程成为端口驱动程序的所有者,并且只有该进程才能与端口驱动程序通信。如果返回 Port ref 并且任何其他进程访问它,则程序可能会崩溃。

更好的方法是您不返回端口。而是将数据作为消息获取并使用相同的 gen_server 读取/写入端口。

于 2013-04-19T16:07:22.417 回答