zoukankan      html  css  js  c++  java
  • erlang supervisor中启动普通的进程

    http://www.cnblogs.com/little-ant/p/3192968.html

    文字部分转自: http://1234n.com/?post/qou3eb

    supervisor的子进程

    一开始使用supervisor的时候,我用的是init/1返回子进程规格列表的方式,并且所有子进程只有两种类型,一种是supervisor进程,一种是gen_server。

    但这次代码重构中,我遇到一个情况。如果我可以启动普通的进程而不是gen_server,我就可以把一些我觉得没必要做成gen_server的模块代码精简掉。因为一些模块代码完全没用到任何gen_server的优势,只是借gen_server来做为supervisor的子进程启动。于是我便开始实验如何在supervisor中启动普通的进程。

    通过实验,我发现我原先对supervisor的理解完全是没有根据的猜测,果然实践才是检验真理的唯一标准。

    首先,我原以为supervisor的子进程规格中提供的Module、Function、Arguments就是子进程的入口,supervisor会通过它来自己启动子进程。但实际上,子进程规格提供的是子进程的启动函数入口,supervisor通过调用这个入口函数来启动子进程,而这个函数通过返回{ok, Pid}来告诉supervisor子进程创建成功。

    其次,并不是简单的通过spawn在子进程启动函数中启动一个进程然后返回{ok, Pid}就可以让子进程拥有出错自动重启的功能。实际上,需要使用proc_lib:spawn_link或者proc_lib:start_link启动子进程,才能在子进程出错退出时让supervisor自动重启它。

    上面的第二点,我是通过阅读gen_server的代码才了解到的,因为一开始我用来做实验的代码没有用spawn(因为第一点的错误理解),但这个问题很容易就发现了,接着我用了spawn看似正确启动了子进程,但实际上这些子进程一旦出错退出就不会再被启动。我换gen_server实验了一遍,确信用gen_server是可以重启的。于是我便阅读gen_server:start_link的代码一探究竟,从源码中可以看到gen_server模块调用gen模块来启动进程,而gen模块最终通过proc_lib:start_link来启动进程。

    proc_lib:start_link和proc_lib:spawn_link的不同之处在于,前者是同步创建子进程,后者是异步创建子进程,proc_lib:start_link调用后会阻塞,直到子进程初始化完毕,调用proc_lib:init_ack后才返回。而proc_lib:spawn_link一调用就会立即返回子进程ID。

    测试代码(其中有和主题无关的测试代码,请大家无视):

    parent_sup.erl

    复制代码
    -module(parent_sup).
    -behaviour(supervisor).
    
    -export([start_link/0]).
    -export([init/1]).
    
    start_link() ->
        supervisor:start_link(?MODULE, []).
    
    init(Args) ->
        {ok, {{one_for_one, 1, 60},
              [%%{child, {child, start_link, ["hello"]},
               %% permanent, brutal_kill, worker, [child]},
               {parent, {parent, start_link, ["args"]},
               permanent, brutal_kill, worker, [parent]}
              ]}}.
    复制代码

    parent.erl

    复制代码
    -module(parent).
    -export([start_link/1]).
    -export([start_loop/1]).
    
    start_link(Args) ->
        io:format("~p~n", [Args]),
        Ret = proc_lib:start_link(?MODULE, start_loop, [self()]),
        io:format("~p~n", [Ret]),
        Ret.
    
    start_loop(Parent) ->
        proc_lib:init_ack(Parent, {ok, self()}),
        loop().
    
    loop() ->
        receive
            Args ->
                io:format("~p~n", [Args])
        end.
    复制代码

    测试命令:

    erl -boot start_sasl

    复制代码
    22> c(parent).
    {ok,parent}
    23> c(parent_sup). parent_sup.erl:10: Warning: variable 'Args' is unused {ok,parent_sup} 24> c(parent). {ok,parent} 25> parent_sup:start_link(). "args" {ok,<0.123.0>} =PROGRESS REPORT==== 16-Jul-2013::11:05:24 === supervisor: {<0.122.0>,parent_sup} started: [{pid,<0.123.0>}, {name,parent}, {mfargs,{parent,start_link,["args"]}}, {restart_type,permanent}, {shutdown,brutal_kill}, {child_type,worker}] {ok,<0.122.0>} 26> exit(pid(0,123,0), some_reason). =SUPERVISOR REPORT==== 16-Jul-2013::11:06:28 === Supervisor: {<0.122.0>,parent_sup} Context: child_terminated Reason: some_reason Offender: [{pid,<0.123.0>}, {name,parent}, {mfargs,{parent,start_link,["args"]}}, {restart_type,permanent}, {shutdown,brutal_kill}, {child_type,worker}] =SUPERVISOR REPORT==== 16-Jul-2013::11:06:28 === Supervisor: {<0.122.0>,parent_sup} Context: shutdown Reason: reached_max_restart_intensity Offender: [{pid,<0.123.0>}, {name,parent}, {mfargs,{parent,start_link,["args"]}}, {restart_type,permanent}, {shutdown,brutal_kill}, {child_type,worker}] ** exception exit: shutdown 27> c(parent). {ok,parent} 28> c(parent_sup). parent_sup.erl:10: Warning: variable 'Args' is unused {ok,parent_sup} 29> parent_sup:start_link(). "args" {ok,<0.138.0>} =PROGRESS REPORT==== 16-Jul-2013::11:07:19 === supervisor: {<0.137.0>,parent_sup} started: [{pid,<0.138.0>}, {name,parent}, {mfargs,{parent,start_link,["args"]}}, {restart_type,permanent}, {shutdown,brutal_kill}, {child_type,worker}] {ok,<0.137.0>} 30> exit(pid(0,138,0), some_reason). "args" =SUPERVISOR REPORT==== 16-Jul-2013::11:07:28 === Supervisor: {<0.137.0>,parent_sup} Context: child_terminated Reason: some_reason Offender: [{pid,<0.138.0>}, {name,parent}, {mfargs,{parent,start_link,["args"]}}, {restart_type,permanent}, {shutdown,brutal_kill}, {child_type,worker}] {ok,<0.140.0>} =PROGRESS REPORT==== 16-Jul-2013::11:07:28 === supervisor: {<0.137.0>,parent_sup} started: [{pid,<0.140.0>}, {name,parent}, {mfargs,{parent,start_link,["args"]}}, {restart_type,permanent}, {shutdown,brutal_kill}, {child_type,worker}] true 31>
    复制代码
  • 相关阅读:
    Activex控件的IObjectSafety接口问题
    用delphi制作无界面的activex控件
    Delphi发布ActiveX控件 制作CAB包 数字签名相关
    Delphi创建ActiveX控件,实现安全接口及无界面代码
    Delphi 开发ActiveX控件(非ActiveForm)
    利用Delphi编写IE扩展
    解决IE9下交通银行网上银行无法输入密码的问题
    Delphi中COM自动化对象中使用事件
    Delphi不注册COM直接使用ActiveX控件并绑定事件
    C#中使用 SendMessage 向非顶端窗体发送组合键
  • 原文地址:https://www.cnblogs.com/fvsfvs123/p/4243720.html
Copyright © 2011-2022 走看看