编程Erlang书中的竞争条件示例

时间:2015-11-05 23:59:06

标签: erlang race-condition

编程Erlang:并发世界的软件一书的第13章末尾,我们得到了一段代码:

keep_alive(Name, Fun) ->
    register(Name, Pid = spawn(Fun)),
    on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).

这本书说:

  • 流程Pid可能会在执行on_exit之前死亡。
  • 如果两个程序同时评估keep_alive并且Name 的值相同,则代码的竞争条件可能会发生

如果两个程序同时使用相同的keep_alive来调用Name,那么register个调用之一将触发badarg异常,因为该名称已被取消,调用过程将会死亡。

因此,进程Pidon_exit被调用之前已经死亡,但进程调用on_exit已经死亡 >

作者的观点是什么,以此为例来描述竞争条件?

1 个答案:

答案 0 :(得分:3)

不,其中实际上可能已经死亡。

Pid引用的过程可能在Fun的第一行有一个错误,它可能会尝试获取一些外部资源作为其第一个操作, 失败(一个锁定的文件,一个不存在的数据库,无论如何),它可以快速终止非常而不需要循环等。

-module(silly).
-export([do_stuff/0]).

do_stuff() ->
   keep_alive(die_bot, fun i_die_fast/0).

i_die_fast() ->
    not_ok = io:format("Is this ok?~n"),
    receive Anything ->
        ok = io:format("Received: ~tp~n", [Anything]),
        i_die_fast()
    end.

keep_alive(Name, Fun) ->
    register(Name, Pid = spawn(Fun)),
    on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).

上面的代码如何发挥出来? (io:format/1始终会返回ok,因此它与not_ok不匹配并在第一行崩溃。)i_die_fast/0似乎永远递归,但它永远不会那么远,可能会在达到on_exit/2之前死亡。 (但是在on_exit/2被调用之前,保证不会死!欢迎来到并发。)

重点是你真的不知道。您可以知道的最接近的是使用spawn_link,或者在较少耦合的情况下使用spawn,然后使用monitorspawn_monitor

register的竞争条件也是如此,可能会使当前正在执行的进程崩溃 - 因此两个竞争条件。

旁注:

这就是为什么我几乎总是拥有衍生的函数寄存器本身,这样如果存在冲突,它就会在孩子的上下文中爆发,而不是调用者(在大多数情况下,你可能有各种各样的原因)想以另一种方式做到这一点):

% Note, we don't need the PID of `some_helper` because it is named.
start() ->
    _ = spawn_link(fun() -> some_helper() end),
    main_loop().

some_helper() ->
    true = register(helper, self()),
    helper_loop().