I'm attempting to implement my own solution for the well known Dijkstra's Dining Philosophers problem. All I'm given is the state machines and that a philosopher should grab both of the forks at the same time.
Here is my code:
-module(assess3).
-compile([export_all]).
-define(EAT,1000).
-define(THINK,1000).
college() ->
R = spawn_link(?MODULE, report,[]),
F1 = spawn_link(?MODULE, fork,["fork1",R]),
F2 = spawn_link(?MODULE, fork,["fork2",R]),
F3 = spawn_link(?MODULE, fork,["fork3",R]),
F4 = spawn_link(?MODULE, fork,["fork4",R]),
F5 = spawn_link(?MODULE, fork,["fork5",R]),
spawn_link(?MODULE, philosopher,["Socrates", R, F1,F2]),
spawn_link(?MODULE, philosopher,["Confucius", R, F2,F3]),
spawn_link(?MODULE, philosopher,["Aristole", R, F3,F4]),
spawn_link(?MODULE, philosopher,["Homer", R, F4,F5]),
spawn_link(?MODULE, sphilosopher,["Plato", R, F1,F5]).
%%create philosophers randomly
philosopher(Name, Report, LeftF, RightF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher
sphilosopher(Name, Report, RightF, LeftF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_special_phil(Name,Report,RightF,LeftF).
%%creates random 4 philosophers who get the Left fork first then the right fork
create_phils(Name,Report,LeftF,RightF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
LeftF ! RightF! {pick,self()},
receive
{pick, LeftF} -> reporting(Report, Name, left);
{pick, RightF} -> reporting(Report, Name, right)
end,
receive
{pick, LeftF} -> reporting(Report, Name, left);
{pick, RightF} -> reporting(Report, Name, right)
end,
%%eating state
reporting(Report,Name,eating),
timer:sleep(random:uniform(?EAT)),
LeftF ! RightF ! {let_go,self()},
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher who attempts to communicate first with the
%%right fork proccess instead of the left fork
create_special_phil(Name,Report,RightF,LeftF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
RightF ! LeftF ! {pick,self()},
receive
{pick, RightF} -> reporting(Report, Name, right);
{pick, LeftF} -> reporting(Report, Name, left)
end,
receive
{pick, RightF} -> reporting(Report, Name, right);
{pick, LeftF} -> reporting(Report, Name, left)
end,
%%eating state
reporting(Report,Name,eating),
timer:sleep(random:uniform(?EAT)),
RightF ! LeftF ! {let_go,self()},
create_special_phil(Name,Report,RightF,LeftF).
%%prepares what the Report proccess will print
reporting(Name,Report,Status) ->
Report ! {Name,Status,self()},
receive
{Report,ack} -> true
end.
%%Report proccess, receives and prints
report() ->
receive
{Name,Status, Pid} ->
io:format("~s : ~s ~n",[Name,status(Status)]),
Pid ! {ack,self()},
report()
end.
%%function to pass the appropriate status in string for io:format
status(Status) ->
case Status of
thinking -> "is thinking";
hungry -> "is hungry";
eating -> "is eating";
right -> "got right fork";
left -> "got left fork";
on_table -> "on table";
in_use ->"in use";
Status -> atom_to_list(Status)
end.
fork(Name,Report) ->
receive
{picked,Pid} ->
reporting(Report,Name,in_use),
Pid ! {picked,self()},
receive
{let_go,Pid} ->
reporting(Report,Name,on_table)
end,
fork(Name,Report)
end.
I get no errors at all but when I try to run assess3:college(). in the Erlang shell, instead of seeing the processes communicate, all I see is this:
Socrates : is thinking
Confucius : is thinking
<0.265.0>
Aristole : is thinking
Homer : is thinking
Plato : is thinking
I do not understand why this occurs, because before I started coding I designed everything by hand in order to avoid getting lost. Any help appreciated.
PS. this implementation is supposed to prevent deadlock because four philosophers grab the left fork first and the 5th one tries to pick the right fork first, although I do understand that this can run into resource starvation meaning that one philosopher might never eat. I don't care about this for now — one step at a time.
You have several problems related to mismatched messages, and function arguments in the wrong order. The mismatched messages cause things to hang waiting forever for messages that are never sent. Fixing those issues then leads to crashes because of the incorrect arguments problem.
For example, consider your fork function:
fork(Name,Report) ->
receive
{picked,Pid} ->
reporting(Report,Name,in_use),
Pid ! {picked,self()},
receive
{let_go,Pid} ->
reporting(Report,Name,on_table)
end,
fork(Name,Report)
end.
It's waiting for a {picked,...} message, but your philosophers are sending {pick,...} messages, and it's replying with a {picked,...} message but the philosophers are expecting to receive {pick,...} messages.
Have a look at your report function:
report() ->
receive
{Name,Status, Pid} ->
io:format("~s : ~s ~n",[Name,status(Status)]),
Pid ! {ack,self()},
report()
end.
It sends an {ack, self()} message back to Pid, but those processes are expecting {Report, ack} messages.
In a number of places you call reporting(Report,Name,...) where the Report and Name arguments are in the wrong order.
Here's a fixed version that seems to work.
-module(assess3).
-compile([export_all]).
-define(EAT,1000).
-define(THINK,1000).
college() ->
R = spawn_link(?MODULE, report,[]),
F1 = spawn_link(?MODULE, fork,["fork1",R]),
F2 = spawn_link(?MODULE, fork,["fork2",R]),
F3 = spawn_link(?MODULE, fork,["fork3",R]),
F4 = spawn_link(?MODULE, fork,["fork4",R]),
F5 = spawn_link(?MODULE, fork,["fork5",R]),
spawn_link(?MODULE, philosopher,["Socrates", R, F1,F2]),
spawn_link(?MODULE, philosopher,["Confucius", R, F2,F3]),
spawn_link(?MODULE, philosopher,["Aristole", R, F3,F4]),
spawn_link(?MODULE, philosopher,["Homer", R, F4,F5]),
spawn_link(?MODULE, sphilosopher,["Plato", R, F1,F5]).
%%create philosophers randomly
philosopher(Name, Report, LeftF, RightF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher
sphilosopher(Name, Report, RightF, LeftF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_special_phil(Name,Report,RightF,LeftF).
%%creates random 4 philosophers who get the Left fork first then the right fork
create_phils(Name,Report,LeftF,RightF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
LeftF ! RightF ! {pick,self()},
receive
{picked, LeftF} -> reporting(Name, Report, left);
{picked, RightF} -> reporting(Name, Report, right)
end,
receive
{picked, LeftF} -> reporting(Name, Report, left);
{picked, RightF} -> reporting(Name, Report, right)
end,
%%eating state
reporting(Name,Report,eating),
timer:sleep(random:uniform(?EAT)),
LeftF ! RightF ! {let_go,self()},
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher who attempts to communicate first with the
%%right fork proccess instead of the left fork
create_special_phil(Name,Report,RightF,LeftF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
RightF ! LeftF ! {pick,self()},
receive
{picked, RightF} -> reporting(Name, Report, right);
{picked, LeftF} -> reporting(Name, Report, left)
end,
receive
{picked, RightF} -> reporting(Name, Report, right);
{picked, LeftF} -> reporting(Name, Report, left)
end,
%%eating state
reporting(Name,Report,eating),
timer:sleep(random:uniform(?EAT)),
RightF ! LeftF ! {let_go,self()},
create_special_phil(Name,Report,RightF,LeftF).
%%prepares what the Report proccess will print
reporting(Name,Report,Status) ->
Report ! {Name,Status,self()},
receive
{Report,ack} -> ok
end.
%%Report proccess, receives and prints
report() ->
receive
{Name,Status,Pid} ->
io:format("~s : ~s ~n",[Name,status(Status)]),
Pid ! {self(),ack},
report()
end.
%%function to pass the appropriate status in string for io:format
status(Status) ->
case Status of
thinking -> "is thinking";
hungry -> "is hungry";
eating -> "is eating";
right -> "got right fork";
left -> "got left fork";
on_table -> "on table";
in_use ->"in use";
Status -> atom_to_list(Status)
end.
fork(Name,Report) ->
receive
{pick,Pid} ->
reporting(Name,Report,in_use),
Pid ! {picked,self()},
receive
{let_go,Pid} ->
reporting(Name,Report,on_table)
end,
fork(Name,Report)
end.
Related
The problem I am trying to solve is as follows:
Write an Erlang function named squared that takes no parameters. This function should wait to receive a message. The message will be in the format { Pid, N }, where you may assume that Pid is a process ID and N is a number. The function should send a message to the process ID Pid in the form { Me, X } where Me is the process ID of the process running the function and X is the value of N squared. The function should then end.
so far I have this:
-module(main).
-export([squared/0]).
squared() ->
receive
{Pid,N} -> Pid ! {Me, X}, squared();
terminate -> ok
end.
The error that I am getting is as follows:
3> c(main).
main.erl:7: variable 'Me' is unbound
main.erl:7: variable 'X' is unbound
main.erl:7: Warning: variable 'N' is unused
error
I am also having trouble in the second part of the problem where it is asking us to send a message to the process ID in the form {Me, X}. Where Me is the process ID and X is the value of N squared. How will we do that?
for implement your function you can write a function like bellow
-module(main).
-export([squared/0]).
squared() ->
receive
{Pid,N} ->
Pid ! {self(), N*N},
squared();
terminate ->
ok
end.
Me should be the pid of the receiving process, i.e. self(). N squared is just N*N.
-module(main).
-export([squared/0]).
squared() ->
receive
{Pid, N} ->
Pid ! {self(), N*N};
terminate -> ok
end.
Or, if you want to be more verbous:
squared() ->
Me = self(),
receive
{Pid, N} ->
X = N * N,
Pid ! {Me, X};
terminate -> ok
end.
Write an Erlang function named calculator that takes no arguments. The function, when run in a process, should wait to receive a message. If the message is in the form of a tuple of four items: { Pid, Operand, X, Y }, do this:
If Operand is add, send a message to Pid with the result of adding X and Y.
If Operand is subtract, send a message to Pid with the result of subtracting Y from X.
If Operand is multiply, send a message to Pid with the result of multiplying X and Y.
If Operand is divide, send a message to Pid with the result of dividing X by Y.
Then, rerun the function.
If the message is in the form of a tuple with two items: { Pid, terminate }, then send a message to Pid of done. Do not rerun the function.
If the message is of any other form, ignore it and rerun the function.
My code:
calculate() ->
receive
{Pid, Operand, X, Y}
if
Operand == "add" -> Pid ! X+Y
Operand == "substract" -> Pid ! Y - X
Operand == "multiply" -> Pid ! X*Y
Operand == "divide" -> Pid ! X/Y
{Pid, terminate} -> Pid ! "done"
_ -> calculate();
end.
Can someone help me with this problem?
Your code does not compile, you should have a look at the basic erlang syntax first.
I give you some clues:
you should not use the if statement for your problem but use pattern matching instead like in
receive
{From,add,X,Y} ->
From ! X+Y,
calculate();
{From,sub,X,Y} ->
...
Generally, for this purpose, use atoms like add rather than string like "add"
you should have a function to start the function calculate/0 in a separate process:
start() ->
spawn(fun() -> calculate() end).
So the idea is that we need to take in a number of child processes to spawn/monitor, but we need to spin up monitor processes such that they only deal with less than 10 child processes at a time. So if we take in 35 child processes, we'd need to have 4 monitors, 3 that monitor 10 children, and one that monitors 5.
The problem is that I'm struggling to figure out why the code I've written for this purpose fails. Here's the code:
-module(watcher).
-import(sensor, [start/0]).
-export([start/1, stop/0]).
start(NrSlaves) ->
MasterPids = [],
MasterPid = spawn(fun() -> master_starter(NrSlaves, MasterPids) end),
register(master, MasterPid),
ok.
stop() ->
master ! die,
ok.
slave_pid_to_nr(SlavePid, SlavePids) ->
slave_pid_to_nr(SlavePid, SlavePids, 1).
slave_pid_to_nr(SlavePid, [SlavePid | _Tail], SlaveNr) ->
SlaveNr;
slave_pid_to_nr(SlavePid, [_Head | Tail], SlaveNr) ->
slave_pid_to_nr(SlavePid, Tail, SlaveNr + 1).
slave_change_pid(OldSlavePid, NewSlavePid, SlavePids) ->
lists:map(
fun(Pid) ->
if
Pid == OldSlavePid ->
NewSlavePid;
true ->
Pid
end
end,
SlavePids
).
%This is the part that errors out
master_starter(NrSlaves, MasterPids) ->
if (NrSlaves/10) =< 1 ->
MasterPids = MasterPids ++ [spawn_link(fun() -> master_start(NrSlaves) end)];
true->
MasterPids = MasterPids ++ [spawn_link(fun() -> master_start(10) end) || lists:seq(1, (NrSlaves/10))],
master_starter(NrSlaves-10, MasterPids)
end,
receive
die ->
io:fwrite("Monitor: received die~n"),
lists:foreach(fun(MasterPid) -> MasterPid ! die end, MasterPids)
end.
master_start(NrSlaves) ->
process_flag(trap_exit, true),
io:fwrite("monitor: started~n", []),
SlavePids = [spawn_link(fun() -> slave_start(SlaveNr) end) || SlaveNr <- lists:seq(1, NrSlaves)],
master_loop(SlavePids).
master_loop(SlavePids) ->
receive
die ->
io:fwrite("Monitor: received die~n"),
lists:foreach(fun(SlavePid) -> SlavePid ! die end, SlavePids);
{SlaveNr, Measurement} ->
io:fwrite("Sensor# ~p measures ~p~n", [SlaveNr, Measurement]),
master_loop(SlavePids);
{'EXIT', SlavePid, _Reason} ->
SlaveNr = slave_pid_to_nr(SlavePid, SlavePids),
io:fwrite("Monitor: Sensor ~p with PID ~p died because of a crash~n", [SlaveNr, SlavePid]),
NewSlavePid = spawn_link(fun() -> slave_start(SlaveNr) end),
NewSlavePids = slave_change_pid(SlavePid, NewSlavePid, SlavePids),
master_loop(NewSlavePids)
end.
slave_start(SlaveNr) ->
% SlavePid = lists:nth(SlaveNr, SlavePids),
io:fwrite("sensor ~p with PID ~p: started~n", [SlaveNr, self()]),
%%slave_loop(SlaveNr).
sensor:start(SlaveNr).
I'm getting errors like: "Error in process <0.573.0> with exit value: {{badmatch,[<0.574.0>]},[{watcher,master_starter,2,[{file,"watcher.erl"},{line,39}]}]}"
Any help would be appreciated. It's very close to being finished, but I just need to understand why this isn't working.
There are three problems I see in your code.
Variables are immutable, and MasterPids = MasterPids ++ ... will fail with badmatch error. Try assigning to new variable like NewPids or MasterPids2.
You are missing generator in you list comprehension. You should have <- somewhere there, like [spawn_link( ... ) || _ <- lists:seq(1, (NrSlaves/10)).
lists:seq do not takes floats. You have to round up NrSlaves/10 to integer. You could use ceiling function from here (maybe simplify a little, since you won't use negative numbers).
Variable are not mutable in erlang. so
MasterPids = MasterPids ++ [spawn_link(fun() -> master_start(NrSlaves) end)];
will fail since you try to modify MasterPids
I have a list construction like this:
[{Value, spawn_link(fun() -> worker(Value, self()) end)} || Value <- List]
So I have a list with values and each value is handed in its own process with the line above. If one worker dies, I want to restart it (with the same value). I have saved the Value in the same tupel as the new process as above. Can I do some list comprehension to determine if the process has died, and in that case, start a new?
Use erlang:monitor/2 to watch for your processes:
List1 = [{Value, spawn_link(fun() -> worker(Value, self()) end)} || Value <- List],
List2 = [{Value, Pid, monitor(process, Pid)} || {Value, Pid} <- List1]
And then wait for messages for monitors, restart your processes if you need and update List2 with new pids and monitors.
To get more info about erlang:monitor/2 read appropriate man page.
In your home made supervisor, don't forget to set process_flag(trap_exit, true) otherwise it will die at the same time one child die, and then all other children too:
1> F = fun() -> timer:sleep(2000) end.
#Fun<erl_eval.20.80484245>
2> F1 = fun() -> timer:sleep(2000), 1/0 end.
#Fun<erl_eval.20.80484245>
3> S = fun() -> spawn_link(F), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
4> S1 = fun() -> spawn_link(F1), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
5> S1b = fun() -> process_flag(trap_exit, true), spawn_link(F1), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
6> self().
<0.40.0>
7> S().
no_message
8> self().
<0.40.0>
9> S1().
=ERROR REPORT==== 15-Mar-2014::06:46:27 ===
Error in process <0.49.0> with exit value: {badarith,[{erlang,'/',[1,0],[]}]}
** exception exit: badarith
in operator '/'/2
called as 1 / 0
10> self().
<0.50.0>
11> S1b().
=ERROR REPORT==== 15-Mar-2014::06:46:39 ===
Error in process <0.53.0> with exit value: {badarith,[{erlang,'/',[1,0],[]}]}
{'EXIT',<0.53.0>,{badarith,[{erlang,'/',[1,0],[]}]}}
12> self().
<0.50.0>
13>
Unless you are doing this for education purpose, I recommend you to use the erlang otp supervisors, with a one_for_one restart strategy.
First, create a function that creates a process that monitors a Pid and executes a Fun when it dies, like so:
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
Fun(Why)
end
end).
Now, you can use the on_exit function to create a function for creating processeses that will restart automatically when the process dies:
keep_alive(Fun) ->
process_flag(trap_exit, true),
Pid = spawn_link(Fun),
on_exit(Pid, fun(Why) ->
io:format("Process died: ~p, restarting it~n", [Why]),
keep_alive(Fun) end),
Pid.
With these little two functions, your work to create processes that will restart automatically is reduced to simply calling keep_alive in your list comprehension:
[{Value, keep_alive(fun() -> worker(Value, self()) end)} || Value <- List].
P.S.: These two little functions are presented almost exactly like this in chapter 13 of the book Programming Erlang 2nd Edition, I only did some minor changes to better suit to your case.
I am new to functional programming and just switched from haskell (Didn't like it much) to erlang (quite fond of it). As I am learning as an autodidact, I stumbled over these Exercises and started doing them.
I came as far as this problem:
Write a function which starts 2 processes, and sends a message M
times forewards and backwards between them. After the messages have
been sent the processes should terminate gracefully.
I resolved it like this and it works (maybe it can be done better; any comment highly appreciated):
-module (concur).
-export ( [pingpong/1, pingpong/2] ).
pingpong (Msg, TTL) ->
A = spawn (concur, pingpong, ["Alice"] ),
B = spawn (concur, pingpong, ["Bob"] ),
B ! {A, TTL * 2, Msg}.
pingpong (Name) ->
receive
{From, 1, Msg} ->
io:format ("~s received ~p and dying.~n", [Name, Msg] ),
exit (From);
{From, TTL, Msg} ->
io:format ("~s received ~p.~n", [Name, Msg] ),
From ! {self (), TTL - 1, Msg},
pingpong (Name)
end.
The real problem is the next exercise:
2) Write a function which starts N processes in a ring, and sends a
message M times around all the processes in the ring. After the
messages have been sent the processes should terminate gracefully.
As I am not sending the message back to its originator, but to the next node in the chain, I somehow have to pass to the sending process the process of the recipient. So I imagined that the function would look something like this:
pingCircle (Name, Next) ->
...
receive {TTL, Msg} -> Next ! {TTL - 1, Msg}
...
But how do I start this whole thing. When I spawn the first function in the circle, I still haven't spawned the next node and hence I cannot pass it as an argument. So my naive approach doesn't work:
First = spawn (concur, pingCirle, ["Alice", Second] ),
Second = spawn (concur, pingCirle, ["Bob", Third] ),
...
Also the approach of passing the spawn call of the next node recursively as a parameter to it predecessor, doesn't solve the problem how to close the circle, i.e. passing the last node to the first.
The question is:
How can I build this circle?
EDIT:
Thanks to your great answers, I managed to what I intended. Hence this question is solved.
One possible solution is:
-module (concur).
-export ( [pingCircle/3, pingCircle/2] ).
pingCircle (Names, Message, TTL) ->
Processes = lists:map (fun (Name) -> spawn (?MODULE, pingCircle, [Name, nobody] ) end, Names),
ProcessPairs = lists:zip (Processes, rot1 (Processes) ),
lists:map (fun ( {Process, Recipient} ) -> Process ! {setRecipient, Recipient} end, ProcessPairs),
Circle = lists:map (fun ( {Process, _} ) -> Process end, ProcessPairs),
hd (Circle) ! {Message, TTL - 1, lists:last (Circle) }.
rot1 ( [] ) -> [];
rot1 ( [Head | Tail] ) -> Tail ++ [Head].
pingCircle (Name, Recipient) ->
receive
{setRecipient, NewRecipient} ->
pingCircle (Name, NewRecipient);
{Message, 0, Originator} ->
io:format ("~s received ~p with TTL 0 and dying.~n", [Name, Message] ),
if
Originator == self () -> io:format ("All dead.~n");
true -> Recipient ! {Message, 0, Originator}
end;
{Message, TTL, Originator} ->
io:format ("~s received ~p with TTL ~p.~n", [Name, Message, TTL] ),
if
Originator == self () -> Recipient ! {Message, TTL - 1, Originator};
true -> Recipient ! {Message, TTL, Originator}
end,
pingCircle (Name, Recipient)
end.
Here is my peer review link.
This exercise has become a rite of passage for all erlang programmers. I gave a working solution to it here, along with an explanation that may be helpful.
Spawn them first, then send them a start signal.
The start signal would be sent after all the processes are already running.
Someone already came up with the answer here -> http://simplehappy.iteye.com/?show_full=true
My answer.
-module(con_test).
start_ring(Msg, M, N) ->
[First|_]=Processes=[spawn(?MODULE, ring, []) || _ <- lists:seq(1,N)],
First ! {rotLeft(Processes), {Msg, M*N}}.
ring() ->
receive
{_List, {Msg, Count}} when Count == 0 ->
io:format("~p got ~s. Enough! I'm out.~n", [self(), Msg]),
exit(normal);
{[Next|_] = List, {Msg, Count}} when Count > 0 ->
io:format("~p got ~s. Passing it forward to ~p.~n", [self(), Msg, Next]),
Next ! {rotLeft(List), {Msg, Count-1}},
ring()
after 1000 ->
io:format("~p is out.~n", [self()]),
exit(normal)
end.
rotLeft([]) -> [];
rotLeft([H|T]) -> T ++[H].