特殊进程

本节将描述如何编写符合OTP设计原理而又不使用标准行为的进程。这样的一种进程要:

  • 以一种可以让进程放入监督树的方式启动,
  • 支持 sys 的 调试功能 ,以及
  • 注意 系统消息 。系统消息是用于监督树中的带有特殊含义的消息。典型的系统消息有跟踪输出的请求、挂起和恢复进程执行的请求(用于发布处理中)。使用标准行为实现的进程会自动处理这些消息。

例子

来自 概述 一章中的简单服务器,如果使用 sysproc_lib 实现并放入一个监督树,则为:

  1. -module(ch4).
  2. -export([start_link/0]).
  3. -export([alloc/0, free/1]).
  4. -export([init/1]).
  5. -export([system_continue/3, system_terminate/4,
  6. write_debug/3]).
  7.  
  8. start_link() ->
  9. proc_lib:start_link(ch4, init, [self()]).
  10.  
  11. alloc() ->
  12. ch4 ! {self(), alloc},
  13. receive
  14. {ch4, Res} ->
  15. Res
  16. end.
  17.  
  18. free(Ch) ->
  19. ch4 ! {free, Ch},
  20. ok.
  21.  
  22. init(Parent) ->
  23. register(ch4, self()),
  24. Chs = channels(),
  25. Deb = sys:debug_options([]),
  26. proc_lib:init_ack(Parent, {ok, self()}),
  27. loop(Chs, Parent, Deb).
  28.  
  29. loop(Chs, Parent, Deb) ->
  30. receive
  31. {From, alloc} ->
  32. Deb2 = sys:handle_debug(Deb, {ch4, write_debug},
  33. ch4, {in, alloc, From}),
  34. {Ch, Chs2} = alloc(Chs),
  35. From ! {ch4, Ch},
  36. Deb3 = sys:handle_debug(Deb2, {ch4, write_debug},
  37. ch4, {out, {ch4, Ch}, From}),
  38. loop(Chs2, Parent, Deb3);
  39. {free, Ch} ->
  40. Deb2 = sys:handle_debug(Deb, {ch4, write_debug},
  41. ch4, {in, {free, Ch}}),
  42. Chs2 = free(Ch, Chs),
  43. loop(Chs2, Parent, Deb2);
  44.  
  45. {system, From, Request} ->
  46. sys:handle_system_msg(Request, From, Parent,
  47. ch4, Deb, Chs)
  48. end.
  49.  
  50. system_continue(Parent, Deb, Chs) ->
  51. loop(Chs, Parent, Deb).
  52.  
  53. system_terminate(Reason, Parent, Deb, Chs) ->
  54. exit(Reason).
  55.  
  56. write_debug(Dev, Event, Name) ->
  57. io:format(Dev, "~p event = ~p~n", [Name, Event]).

以及如何在 ch4 中使用 sys 中的简易调试函数:

  1. % erl
  2. Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]
  3.  
  4. Eshell V5.2.3.6 (abort with ^G)
  5. 1> ch4:start_link().
  6. {ok,<0.30.0>}
  7. 2> sys:statistics(ch4, true).
  8. ok
  9. 3> sys:trace(ch4, true).
  10. ok
  11. 4> ch4:alloc().
  12. ch4 event = {in,alloc,<0.25.0>}
  13. ch4 event = {out,{ch4,ch1},<0.25.0>}
  14. ch1
  15. 5> ch4:free(ch1).
  16. ch4 event = {in,{free,ch1}}
  17. ok
  18. 6> sys:statistics(ch4, get).
  19. {ok,[{start_time,{{2003,6,13},{9,47,5}}},
  20. {current_time,{{2003,6,13},{9,47,56}}},
  21. {reductions,109},
  22. {messages_in,2},
  23. {messages_out,1}]}
  24. 7> sys:statistics(ch4, false).
  25. ok
  26. 8> sys:trace(ch4, false).
  27. ok
  28. 9> sys:get_status(ch4).
  29. {status,<0.30.0>,
  30. {module,ch4},
  31. [[{'$ancestors',[<0.25.0>]},{'$initial_call',{ch4,init,[<0.25.0>]}}],
  32. running,<0.25.0>,[],
  33. [ch1,ch2,ch3]]}