io:getline(Prompt)in spawned process:提示不显示

时间:2019-02-02 00:30:54

标签: erlang

代码如下:

-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> 

有人可以解释第一个示例中发生了什么竞赛情况吗?

1 个答案:

答案 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>