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> 

时间: 2024-08-28 19:19:26

erlang supervisor中启动普通的进程的相关文章

[Erlang_Question13]怎么把一个普通的进程挂入Supervisor监控树?

简单来说:应该是在调用的start_link返回一个{ok,Pid}就可以把这个进程放入监控树Supervisor里面: -module(worker). -author("[email protected]"). -export([start_link/0,stop_worker/0]). start_link() –> {ok,spawn(fun() -> loop() end)}. loop() –> case whereis(?MODULE) of undef

Win7中如何在服务中启动一个当前用户的进程——函数CreateProcessAsUser()的一次使用记录

这次工作中遇到要从服务中启动一个具有桌面UI交互的应用,这在winXP/2003中只是一个简单创建进程的问题.但在Vista 和 win7中增加了session隔离,这一操作系统的安全举措使得该任务变得复杂了一些. 一.Vista和win7的session隔离 一个用户会有一个独立的session.在Vista 和 win7中session 0被单独出来专门给服务程序用,用户则使用session 1.session 2... 这样在服务中通过CreateProcess()创建的进程启动UI应用用

Win7中如何在服务中启动一个当前用户的进程——一次CreateProcessAsUser()使用记录

这次工作中遇到要从服务中启动一个具有UI交互的桌面应用,这在winXP/2003中只是一个简单创建进程的问题.但在Vista 和 win7中增加了session隔离,这一操作系统的安全举措使得该任务变得复杂了一些. 一.Vista和win7的session隔离 一个用户会有一个独立的session.在Vista 和 win7中session 0被单独出来专门给服务程序用,用户则使用session 1.session 2... 这样在服务中通过CreateProcess()创建的进程启动UI应用用

在linux中安装jdk以及tomcat并shell脚本关闭启动的进程

在命令行模式中输入uname -a ,如下图,当界面展示i386就说明本linux系统为32版本,就在官网下载对应jdk版本,或者直接到我的网盘上下载http://pan.baidu.com/s/1cqMNd8 将下载好的tar包通过rz命令上传到服务器路径/usr/local下并通过命令解压:tar -xf jdk-7u67-linux-i586.tar.gz 编辑系统隐藏文件profile文件并添加jdk的path,命令:vi /etc/profile,在打开的界面通过i命令在该闻文本的结尾

Android系统在新进程中启动自定义服务过程(startService)的原理分析

在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验.Android系统为我们提供了一个Service类,我们可以实现一个以Service为基类的服务子类,在里面实现自己的计算型逻辑,然后在主进程通过startService函数来启动这个服务.在本文中,将详细分析主进程是如何通过startService函数来在新进程中启动自定义服务的. 在主进程调用startService函数时,会通过Binder进程间通信机制来

Android应用程序在新的进程中启动新的Activity的方法和过程分析

Android应用程序在新的进程中启动新的Activity的方法和过程分析 - 老罗的Android之旅 - 博客频道 - CSDN.NET ? ? ? ?前面我们在分析Activity启动过程的时候,看到同一个应用程序的Activity一般都是在同一个进程中启动,事实上,Activity也可以像Service一样在新的进程中启动,这样,一个应用程序就可以跨越好几个进程了,本文就分析一下在新的进程中启动Activity的方法和过程. ?? ? ? ?在前面Android进程间通信(IPC)机制B

C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思?

原文:C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思? 在 .NET 中创建进程时,可以传入 ProcessStartInfo 类的一个新实例.在此类型中,有一个 UseShellExecute 属性. 本文介绍 UseShellExecute 属性的作用,设为 true 和 false 时,分别有哪些进程启动行为上的差异. 本文内容 本质差异 效果差异 如何选择 本质差异 Process.Start 本质上是启动一个新的

【转】遍历Taskmanager中所有的进程是否已经启动需要的exe

CreateToolhelp32Snapshot CreateToolhelp32Snapshot函数为指定的进程.进程使用的堆[HEAP].模块[MODULE].线程[THREAD])建立一个快照[snapshot]. HANDLE WINAPI CreateToolhelp32Snapshot( DWORD dwFlags, //用来指定"快照"中需要返回的对象,可以是TH32CS_SNAPPROCESS等 DWORD th32ProcessID //一个进程ID号,用来指定要获取

使用supervisor监控mha masterha_manager进程

我们在用mha自带的masterha_manager脚本做mysql主库故障自动切换时,需要考虑如何让masterha_manager监控进程一直处于正常运行的状态.而supervisor可以很好地解决这个问题,它可以将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启. 这里列一下部署要点和管理命令 一,supervisor 安装: sudo pip install supervisor 二,supervisor配置: mkdir -p /etc/superviso