我有以下程序。但是,在跟踪生成的进程时,我看到一条带有超时的跟踪消息,如下面的跟踪所示。
start() ->
register(addone, spawn(addone, loop, [])).
loop() ->
receive
{request, Pid, Msg} ->
io:format("log ~n", []),
loop();
{stop, _Reason} ->
stop
end.
我正在使用以下函数执行此过程:
run() ->
addone:start(),
dbg:start(),
dbg:tracer(),
dbg:p(whereis(addone), [c,m]),
dbg:tpl({'_','_','_'},[{'_',['true'],[{'silent', 'false'}]}]),
addone:request(4).
观察到的痕迹如下:
1> addone_scenarios:run().
log
(<0.32.0>) << {request,<0.30.0>,4}
(<0.32.0>) call io:format("log ~n",[])
(<0.32.0>) call io:default_output()
(<0.32.0>) call erlang:group_leader()
(<0.32.0>) call io:format(<0.23.0>,"log ~n",[])
(<0.32.0>) call io:o_request(<0.23.0>,{format,"log ~n",[]},format)
(<0.32.0>) call io:request(<0.23.0>,{format,"log ~n",[]})
(<0.32.0>) call io:io_request(<0.23.0>,{format,"log ~n",[]})
(<0.32.0>) call io:bc_req(<0.23.0>,{put_chars,unicode,io_lib,format,["log ~n",[]]},false)
(<0.32.0>) call net_kernel:dflag_unicode_io(<0.23.0>)
(<0.32.0>) call io:execute_request(<0.23.0>,{false,{put_chars,unicode,io_lib,format,["log ~n",[]]}})
(<0.32.0>) call erlang:monitor(process,<0.23.0>)
(<0.32.0>) <0.23.0> ! {io_request,<0.32.0>,<0.23.0>,
{put_chars,unicode,io_lib,format,["log ~n",[]]}}
(<0.32.0>) call io:wait_io_mon_reply(<0.23.0>,#Ref<0.0.0.29>)
(<0.32.0>) << {io_reply,<0.23.0>,ok}
(<0.32.0>) call erlang:demonitor(#Ref<0.0.0.29>)
(<0.32.0>) << timeout
(<0.32.0>) call addone:loop()
奇怪的是收到的超时跟踪消息。当我删除io:format(...)
时,未收到此消息。有人可以说明原因可以吗?
编辑:我已更新跟踪以包含对所有功能的调用,可能会有所帮助。
答案 0 :(得分:1)
io模块中唯一一个在函数io:wait_io_mon_reply/2
中有超时的地方,它等待对io请求消息的回复。为了确保客户端进程永远不会挂起,io进程已被监视,以检测它在返回应答之前死亡的情况。 io:wait_io_mon_reply/2
必须处理它可以接收的各种情况 AND 还清除消息队列,以防它获得多次返回,例如回复消息和进程死亡消息在监控关闭之前发送。由于erlang通信的非确定性异步性质,这种情况发生了,必须要注意。
处理此问题的标准方法是(直接从函数中取出):
receive
{io_reply, From, Reply} ->
erlang:demonitor(Mref),
receive
{'DOWN', Mref, _, _, _} -> true
after 0 -> true
end,
Reply;
使用0
的超时意味着你永远不会等待消息不在那里但你确实会超时。我猜这是你在跟踪中看到的。这不是错误,而是编写代码的方式。这样做没有可行的替代方案。
这意味着在某种程度上你必须忽略这个超时,或者只是接受超时作为程序的自然部分而不是某种形式的“异常”或错误。
如果我了解它是如何运作的。
答案 1 :(得分:0)
我的两分钱:如果你读dbg的erlang doc,你也会看到超时消息,我的意见是注册打印调试消息的io_server产生了一个专用的进程,可以简化大量阻塞I / O跟踪的性能,但是一段时间后没有任何内容被跟踪,它只是删除了监听'套接字'(我的意思是从erlang传递消息系统的角度看套接字)。 实际上,您可以看到io_request和io_reply与之相关的&lt; 0.23.0&gt;这是打印服务器,我认为你可以简单地忽略它作为(无用的)进一步的调试消息。