Link and Monitor differences

Introduction

link/1 and monitor/2 are 2 different ways of notifying (or know) that a process died. Thing is, these are really very different in nature and these differences are not widely understood by beginners. So let's shed some light on this subject!

Linking to a process

Links are what makes it possible to have supervisor trees. As stated in the Error Handling section of the processes reference manual:

Erlang has a built-in feature for error handling between processes. Terminating processes will emit exit signals to all linked processes, which may terminate as well or handle the exit in some way.

The signal in question is the exit signal, and the links make this signal propagate through processes (i.e: up in the supervisor hierarchy). By default, this signal makes your processes terminate as well. Assume the following code:

  1. -module(mymodule).
  2. start_link() ->
  3. gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  4. ...
  5. crash() ->
  6. gen_server:cast(?MODULE, crash).
  7. ...
  8. handle_cast(crash,State) ->
  9. {stop, error, State};
  10. ...

Let's spawn of those, and try to link our shell to it:

  1. 1> self().
  2. <0.31.0>
  3. 2> mymodule:start_link().
  4. {ok,<0.34.0>}
  5. 3> mymodule:crash().
  6. =ERROR REPORT==== 30-Dec-2012::15:36:47 ===
  7. ** Generic server a terminating
  8. ** Last message in was {'$gen_cast',crash}
  9. ** When Server state == []
  10. ** Reason for termination ==
  11. ** error
  12. ** exception exit: error
  13. 4> self().
  14. <0.36.0>

As you can see, using gen_server:start_link/4 automatically creates a link between our shell and the newly started process. So when this new process terminates, our shell gets an exit signal, also crashes, but it gets automatically restarted (note how the self() code returned 2 different pids).

The Receiving Exit Signals section of the processes reference manual gives some more information:

The default behaviour when a process receives an exit signal with an exit reason other than normal, is to terminate and in turn emit exit signals with the same exit reason to its linked processes. An exit signal with reason normal is ignored.

A process can be set to trap exit signals by calling:

process_flag(trap_exit, true)

When a process is trapping exits, it will not terminate when an exit signal is received. Instead, the signal is transformed into a message {'EXIT',FromPid,Reason} which is put into the mailbox of the process just like a regular message.

Let's now try the same thing, but capturing the exit signal with process_flag/2

:

  1. 1> process_flag(trap_exit, true).
  2. false
  3. 2> self().
  4. <0.31.0>
  5. 3> mymodule:start_link().
  6. {ok,<0.35.0>}
  7. 4> mymodule:crash().
  8. ok
  9. 5>
  10. =ERROR REPORT==== 30-Dec-2012::15:51:20 ===
  11. ** Generic server mymodule terminating
  12. ** Last message in was {'$gen_cast',crash}
  13. ** When Server state == []
  14. ** Reason for termination ==
  15. ** error
  16. 5> self().
  17. <0.31.0>
  18. 6> receive X->X end.
  19. {'EXIT',<0.35.0>,error}

As you can see, the shell didn't died, but got a message instead. Cool!

To sum up, and to quote the Processes entry in the OTP reference manual:

    • Two processes can be linked to each other. A link between two processes Pid1 and Pid2 is created by Pid1 calling the BIF link(Pid2) (or vice versa).
    • Links are bidirectional and there can only be one link between two processes. Repeated calls to link(Pid) have no effect.
    • The default behaviour when a process receives an exit signal with an exit reason other than normal, is to terminate and in turn emit exit signals with the same exit reason to its linked processes.
    • An exit signal with reason normal is ignored.

As a final note to links, there are a couple of interesting functions to know about:

Monitoring a process

Monitors are not links, they are a more relaxed way of knowing what happened to a process.

They use messages instead of signals, and these messages are not propagated like signals, so nothing happens to your process when a monitored process exits (except that you get a new message in your mailbox). Also, they are unidirectional and allow you to establish as many "monitors" as you want (remember how links limited the number of links between 2 processes to just 1). Quoting the manual:

An alternative to links are monitors. A process Pid1 can create a monitor for Pid2 by calling the BIF erlang:monitor(process, Pid2). The function returns a reference Ref.

If Pid2 terminates with exit reason Reason, a 'DOWN' message is sent to Pid1:

{'DOWN', Ref, process, Pid2, Reason}

Monitors are unidirectional. Repeated calls to erlang:monitor(process, Pid) will create several, independent monitors and each one will send a 'DOWN' message when Pid terminates.

Now, to the very same source code we tried above, let's modify it to add a start/0 function:

  1. -module(mymodule).
  2. start() ->
  3. gen_server:start({local, ?MODULE}, ?MODULE, [], []).
  4. ...
  5. start_link() ->
  6. gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  7. ...
  8. crash() ->
  9. gen_server:cast(?MODULE, crash).
  10. ...
  11. handle_cast(crash,State) ->
  12. {stop, error, State};
  13. ...

Note the new start/0 call that uses gen_server:start/4 instead of gen_server:start_link/4, so we can avoid having our shell linked to the new process when trying it.

Let's try it in the shell:

  1. 1> self().
  2. <0.31.0>
  3. 2> mymodule:start().
  4. {ok,<0.34.0>}
  5. 3> process_flag(trap_exit, true).
  6. false
  7. 4> erlang:monitor(process, mymodule).
  8. #Ref<0.0.0.43>
  9. 5> mymodule:crash().
  10. ok
  11. =ERROR REPORT==== 30-Dec-2012::16:21:29 ===
  12. ** Generic server mymodule terminating
  13. ** Last message in was {'$gen_cast',crash}
  14. ** When Server state == []
  15. ** Reason for termination ==
  16. ** error
  17. 6> receive X->X end.
  18. {'DOWN',#Ref<0.0.0.43>,process,{mymodule,nonode@nohost},error}

So our shell, while still was informed about the exit of the other process, didn't die (because it didn't got an exit signal).

A couple of interesting functions related to monitoring:

To link or to monitor: That is the question

So this brings up the question: should I link to or monitor my processes? Of course the answer is 42.. I mean, it depends. Use link if you:

      • Have a dependency on a process (i.e: you can't run if a specific process dies). This fits great into supervisor trees.
      • Have a bidirectional dependency, where a parent can't run if the child dies, and you also want to kill the child if the parent dies in turn.
      • Only need 1 link between processes (remember that if A and B are linked, all subsequent calls to link/2 will be ignored).
      • You are a supervisor, or you want some kind of physical relationship between your processes in your architecture (i.e: you actually need to die or restart or try something out to fix the situation that led to the death of your child.

Use monitor if you:

      • Just want to know if a specific process is running, but it's ok for you to continue execution without it (i.e: you can just send an alarm and keep going).
      • Don't need a bidirectional relation (i.e: you want A to know about B dying but you don't need B to know about A).
      • You are an external process, just interested in the faith of a particular process

【转载】Erlang 中 link 和 monitor 的区别的更多相关文章

  1. [转载]C++中声明与定义的区别

    C++学了这么多年你知道为什么定义类时,类的定义放在.h文件中,而类的实现放在cpp文件中.它们为什么能够关联到一起呢?你知道什么东西可以放在.h文件中,什么不能.什么东西又可以放在cpp文件中.如果 ...

  2. CSS中link与import的区别

    一.import的用法 1,在html文件中 <style type="text/css"> @import url(http://www.dreamdu.com/st ...

  3. AngularJS自定义Directive中link和controller的区别

    在AngularJS中,自定义Directive过程中,有时用link和controller都能实现相同的功能.那么,两者有什么区别呢? 使用link函数的Directive 页面大致是: <b ...

  4. AngularJs 指令 directive中link,controller 的区别

    其实严格来讲,link和controller是完全不同的概念,这里讲区别有点牵强. angular指令中,带有link和controller两个函数,很多人在写指令的时候不知道是写在link里 还是c ...

  5. HTML网页设计中 link 和 @import 的区别

    页面中使用CSS的方式主要有3种:行内添加定义style属性值,页面头部内嵌调用和外面链接调用,其中外面引用有两种:link和@import.外部引用CSS两种方式link和@import的方式分别是 ...

  6. 转载http中302与301的区别

    http://blog.csdn.net/qmhball/article/details/7838989 一.官方说法301,302 都是HTTP状态的编码,都代表着某个URL发生了转移,不同之处在于 ...

  7. 【对比分析三】CSS中 link 和@import 的区别

    1).  link 是 XHTML 标签,无兼容问题: @import 是在 CSS2.1 提出的,只有IE5以上才能识别. 2).  语法结构不同. link (链接式)只能放入HTML源码中,语法 ...

  8. 外部引用CSS中 link与@import的区别

    差别1:link属于XHTML标签,而@import完全是CSS提供的一种方式. link标签除了可以加载CSS外,还可以做很多其它的事情,比如定义RSS,定义rel连接属性等,@import就只能加 ...

  9. [转载]jquery中attr和prop的区别

    在高版本的jquery引入prop方法后,什么时候该用prop?什么时候用attr?它们两个之间有什么区别?这些问题就出现了. 关于它们两个的区别,网上的答案很多.这里谈谈我的心得,我的心得很简单: ...

随机推荐

  1. 【leetcode】Letter Combinations of a Phone Number

    Letter Combinations of a Phone Number Given a digit string, return all possible letter combinations ...

  2. Effecvtive C++笔记:让自己习惯C++

    条款01:视C++为一个语言联绑 C++的四个语言层次: C:C++是以C为基础的.基本数据类型.语句.预处理器.数组.指针等统统来自C. Oject-Oriented C++:面向对象这一特性包含了 ...

  3. iOS 转载一篇利用dispatch_once创建单例的文章

    感谢文章原作者,http://bj007.blog.51cto.com/1701577/649413

  4. ORACLE清除某一字段重复的数据(选取重复数据中另一个字段时期最大值)

    需求:资产维修表中同一资产可能维修完继续申请维修,这时候维修状态需要根据最近的维修时间去判断维修状态,所以同一资产ID下会出现重复的数据(维修审批通过,维修审批未通过),或者可能不出现(未申请维修), ...

  5. July 14th, Week 29th Thursday, 2016

    Risk comes from not knowing what you are doing. 风险常常来自于不知道自己在做什么. What is risk? I think risk means t ...

  6. 越狱后天气闪退 iPhone5天气闪退解决方法

    iPhone5天气闪退解决方法: 第一步:前往Cydia卸载AppSync; 第二步:通过iTools删除/var/mobile/Library/Caches/com.apple.mobile.ins ...

  7. Android实现网络音乐播放器

    本文是一个简单的音乐播放器 布局代码 <?xml version="1.0" encoding="utf-8"?> <RelativeLayo ...

  8. phpcms分页使用

    #pages { padding: 14px 10px; font-family: 宋体; } .text-c { text-align: center; } #pages span { displa ...

  9. VS2010编写动态链接库DLL及单元测试用例,调用DLL测试正确性

    转自:http://blog.csdn.net/testcs_dn/article/details/27237509 本文将创建一个简单的动态链接库,并编写一个控制台应用程序使用该动态链接库,该动态链 ...

  10. Android控件系列之RadioButton&RadioGroup(转)

    学习目的: 1.掌握在Android中如何建立RadioGroup和RadioButton 2.掌握RadioGroup的常用属性 3.理解RadioButton和CheckBox的区别 4.掌握Ra ...