Long story short I am trying to replicate the Sleeping barber problem in Erlang.
In my solution I decided that for all the processes that are waiting I would put them into a list. Then, once it was that process开发者_如何学JAVAes turn, I would take that PID off of the list.
Unfortunately when I call
length(myListOfPids).
it fails, as an example:
length([<0.46.0>]).
* 2: syntax error before: '<'
is there a way to store PID's so that I can recall them and use them normally? i.e.
PID ! message
... just in case it matters here is the actual error I recieve when running my program:
=ERROR REPORT==== 1-Jul-2010::05:50:40 ===
Error in process <0.44.0> with exit value:
{badarg,[{erlang,length,[<0.46.0>]},{barber1,waitingRoom,2}]}
barber1 is my module, waitingRoom is the function that keeps track of which processes are waiting
You can also construct a Pid from it's three components using pid/3.
1> length([pid(0,35,0)]).
Be aware that using any of these techniques for constructing Pid goes wrong if you construct a pid on a different node than the one it was created on.
The problem your program is having is different.
{badarg,[{erlang,length,[<0.46.0>]},{barber1,waitingRoom,2}]}
A call to erlang:length/1 created a badarg. The third element of {erlang,length,[<0.46.0>]} is the list of arguments passed to erlang:length. So that's equivalent to:
1> erlang:length(pid(0,46,0)).
where you intended:
1> erlang:length([pid(0,46,0)]).
(Annoyingly, the erlang shell now hides erlang's internal representation of errors from you. Replacing the above error with:
** exception error: bad argument in function length/1 called as length(<0.35.0>)
which is much easier to understand but less useful because it gets in the way of learning the essential skill of interpreting erlang errors yourself.)
Entering Pids by typing them does not work for me either. Is that the only problem?
With code:
-module(test).
-export([loop/0]).
loop() ->
receive
{hello} ->
io:format("Hello world!~n"),
loop()
end.
I get:
Eshell V5.7.5 (abort with ^G)
1> Pid = spawn(fun test:loop/0).
<0.35.0>
2> L = [Pid].
[<0.35.0>]
3> length(L).
1
This error message:
=ERROR REPORT==== 1-Jul-2010::05:50:40 ===
Error in process <0.44.0> with exit value:
{badarg,[{erlang,length,[<0.46.0>]},{barber1,waitingRoom,2}]}
means that you were calling length(<0.46.0>)
, not length([<0.46.0>])
(ignoring for the moment that PIDs can only be written, not read). In the stack trace the topmost function will have the list of arguments. Since length
takes one argument, this list has a single argument: you are taking the length of a PID, which obviously fails, since only lists have lengths.
The problem is that while <0.46.0>
is the way that a PID gets printed, it can't be entered this way. You can use list_to_pid("<0.46.0>")
instead. Of course, once you do have a PID (created in this way, returned from spawn
, etc.), it can be stored in a list and retrieved like any other Erlang term.
The standard way to get a pid is to take the return value of a spawn function, either spawn/1
, spawn/3
, spawn_link/1
, spawn_link/3
, and the proc_lib
equivalents.
A simple way to write down a pid is with the function c:pid/3, called like c:pid(0,25,0)
, which will return <0.25.0>
. That's a shortcut function for the shell. Otherwise, you can use list_to_pid/1
as mentioned by Alexey Romanov.
However, you should be aware of the role of pids before trying to build them by hand. The pid acts as the personal identifier of a process and is meant to be used only by those who know about it. If you don't have the pid in your hand already, then you likely shouldn't be in its possession already. Indirectly, this is meant to lead to insulation of different parts of a program — only care about those bits that you spawned and have each part of your program mind its own business.
The cleanest way to do it is thus to use the return value of a spawn function. Generating a pid by hand should be left as a debugging solution only.
精彩评论