I'm testing the code in Getting Started with Erlang User's Guide Concurrent Programming Section.
In tut17.erl
, I started a process with erl -sname ping
, and another process with al -sname pong
as the guide described.
-module(tut17).
-export([start_ping/1, start_pong/0, ping/2, pong/0]).
ping(0, Pong_Node) ->
{pong, Pong_Node} ! finished,
io:format("ping finished~n", []);
ping(N, Pong_Node) ->
{pong, Pong_Node} ! {ping, self()},
receive
pong ->
io:format("Ping received pong~n", [])
end,
ping(N - 1, Pong_Node).
pong() ->
receive
finished -> io:format("Pong finished~n", []);
{ping, Ping_PID} ->
io:format("Pong received ping~n", []),
Ping_PID ! pong,
pong()
end.
start_pong() ->
register(pong, spawn(tut17, pong, [])).
start_ping(Pong_Node) ->
spawn(tut17, ping, [3, Pong_Node]).
From the ping and pong process, I could invoke the start_ping and start_pong to check everything works fine.
(ping@smcho)1> tut17:start_ping(pong@smcho).
<0.40.0>
Ping received pong
Ping received pong
Ping received pong
ping finished
(pong@smcho)2> tut17:start_pong().
true
Pong received ping
Pong received ping
Pong received ping
Pong finished
I'm trying to run the same code from a command line; For a simple hello world example:
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("Hello, world!\n").
I use the following command line:
erlc helloworld.erl
erl -noshell -s helloworld start -s init stop
So, I just tried with the following, but ended up with a crash.
erl -noshell -sname ping -s tut17 start_ping pong@smcho -s init stop
erl -noshell -sname pong -s tut17 start_pong -s init stop
However, I got this error report from the ping
when pong
ends without printing anything.
=ERROR REPORT==== 6-Mar-2015::20:29:24 ===
Error in process <0.35.0> on node 'ping@smcho' with exit value:
{badarg,[{tut17,ping,2,[{file,"tut17.erl"},{line,9}]}]}
Compared to the REPL approach, with command line, each process does not wait for the counterpart to response, but stops after some time. What might be wrong?
Arguments from the command line are received as a list of atoms when using the -s
switch, and a list of strings when using the -run
switch. With this in mind, let's think through what happens...
This command is issued from the shell:
erl -noshell -sname ping \
-s tut17 start_ping pong@smcho \
-s init stop
So start_ping/1
is being called with the argument [pong@smcho]
. It is then calling ping/2
as ping(3, [pong@smcho])
, which in its first line tries to do {pong, [pong@smcho]} ! {ping, self()}
. Because a list is not a valid target for a message... your world explodes.
To run this both from the Erlang shell and the system shell comfortably you could add a clause to start_ping/1
:
start_ping([Pong_Node]) ->
spawn(tut17, ping, [3, Pong_Node]);
start_ping(Pong_Node) ->
start_ping([Pong_Node]).