代码如下:
-module(my).
-compile(export_all).
test() ->
register(go, spawn(my, init, []) ).
init() ->
Reply = io:get_line("enter:"),
io:format("Reply= ~s~n", [Reply]).
在外壳中:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
true
3>
如果我在此处添加timer:sleep()
:
test() ->
register(go, spawn(my, init, []) ).
init() ->
timer:sleep(1000), %%<<<==========HERE
Reply = io:get_line("enter:"),
io:format("Reply= ~s~n", [Reply]).
并在shell中运行新代码,然后在1秒钟后,第一个示例的输出中的shell提示3>
突然消失,并由enter:
代替:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
true
enter:
如果我输入了一些内容,那么按预期,我会看到Reply= xx
。
如果我将timer:sleep()
移到此处:
test() ->
register(go, spawn(my, init, []) ),
timer:sleep(1000). %%<<======HERE
init() ->
Reply = io:get_line("enter:"),
io:format("Reply= ~s~n", [Reply]).
然后我在外壳中运行代码,我看到了:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
enter:
然后enter:
突然消失,并被ok
取代:
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
ok
3>
此可以正常运行:
1> Reply = io:get_line("enter: ").
enter: hello
"hello\n"
2> Reply.
"hello\n"
3>
有人可以解释第一个示例中发生了什么竞赛情况吗?
答案 0 :(得分:0)
实际上,这并非完全是比赛条件。出现此问题的原因是,我们只有一个std_in流,并且在给定时间内只有一个进程可以使用它。
1)在第一个代码段中,“ go”首先使用get_line / 1函数对std_in进行控制。但是,在该test / 0函数返回到Erlang shell之后,shell在std_in下进行了控制(Erlang shell正在等待带有“>”之类的提示的用户输入)。因此,进程“ go”现在与std_in取消链接,并且不会从std_in接收任何字符。所有输入都进入Erlang shell。
2)第二个片段在init / 1中具有sleep / 1功能。因此情况恰恰相反。我们允许Erlang shell到达等待输入状态,然后在“ go”过程中执行get_line / 1。因此,现在“执行”过程可以控制std_in并从键盘接收字符。但是'go'进程终止后,Erlang shell将恢复其状态。
3)第三个片段只是第一个片段,但带有sleep / 1功能的情况更加严重。
4)没有解释第四段代码。它按预期工作。
5)为了说明这种观点,您可以运行以下代码:
-module(my).
-compile(export_all).
test() ->
spawn_link(my, init1, []),
spawn_link(my, init2, []).
init1() ->
timer:sleep(100),
init(0, "0").
init2() ->
timer:sleep(100),
init(0, "1").
init(N, Title) ->
% io:format(">>init(~p)~n", [N]),
Reply = io:get_line(Title ++ "> enter:"),
io:format("[~s] (e - exit) Reply= ~s", [Title, Reply]),
case Reply of
"e\n" -> ok;
_ -> init(N+1, Title)
end.
该模块使用get_line / 1启动两个进程。但只有最近一个进程可以除外std_in的输入:
50> my:test().
<0.192.0>
1> enter:w
[1] (e - exit) Reply= w
1> enter:d
[1] (e - exit) Reply= d
1> enter:e
[1] (e - exit) Reply= e
0> enter:dd
[0] (e - exit) Reply= dd
0> enter:e
[0] (e - exit) Reply= e
51>