Jump to content

Dining philosophers: Difference between revisions

no edit summary
No edit summary
Line 3,865:
 
:- end_object.</lang>
=={{header|M2000 Interpreter}}==
There are two kind of threads depends on thread plan. Each thread triggered in an interval. When the plan in sequwntial all the thread code executed. When the plan is concurrent then for each statement or block of code (in brackets) executed and then pass the execution to a thread mananager, so may another thread execute statement or block of statement. M2000 Intepreter compiled in Visual Basic 6 so its a single thread application, so threads are scheduled via a task manager inside interpreter. Any function we call from a thread executed stopping the polling of threads from task manager.
 
To handle deadlock we have to alter the way which a philosopher get the first fork, so we have a R variable to hold true (-1) if the right fork taken first. To get the other fork a philosopher must get the first one. The time for thinking varies. Also the time which a philosopher enter to table varies too.
 
In the output we have time in milliseconds when the philosopher status show eating or thinking.
 
Threads are code running in same scope when defined. From a thread we can see any variable or function or other modules local to module, but not the static variables of module because a thread has own static variables. Also we can change the time interval from the thread, and we do that defining the eating time and the thinking time. If we place all philosophers with R=0 we get soon a deadlock. Some philosophers eat more than other, but this depends on how long stay at thinking (maybe X1 to X5 of a base thinking time)
 
The Main.Task is a thread which display the eating counting for each philosopher, and the table with five values (Fork or No Fork). Also there is a counter which advance if table has no Forks and reset to zero if one or more forks exist. So if we get a deadlock the program stops after some seconds.
 
We can press Esc to stop program, or we can press right mouse button to stop it from code. In either way threads erased. If the code is in module A we can execute from M2000 console Test A to execute it diplaying the code, including the code in threads. We can execute statement by statement also pressing Next Step in Control Form (opened with Test statement).
 
 
<lang M2000 Interpreter>
Module Dining_philosophers (whichplan) {
Form 80, 32
Document Doc$
const nl$={
}
Print $(,12), ' set column width to 12
Pen 14
Pen 15 {
Doc$="Dining Philosophers"+nl$
\\ we can change thread plan only if no threads defined
if whichplan=1 then
Doc$="Sequential threads - to execute exclusive one threads code"+nl$
thread.plan sequential
\\ need time_to_think>time_to_eat, but time_to_appear maybe the same for all
time_to_think=150 ' one or more intervals
time_to_eat=100 ' one interval to eat only
time_to_appear=(150,150,150,150,150)
Return time_to_appear, random(0,3):=300
else
Doc$="Concurrent threads - to execute a statement or a block of code"+nl$
thread.plan concurrent
time_to_think=100 ' one or more intervals
time_to_eat=50 ' one interval to eat only
time_to_appear=(100,100,100,100,100)
Return time_to_appear, random(1,4):=200
end if
Print #-2,Doc$
Print @(0,2),"Press left mouse button to exit"
}
Pen 13 {Print "Aristotle", "Kant", "Spinoza", "Marx", "Russell"}
enum philosopher {
Aristotle, Kant, Spinoza, Marx, Russell
}
global enum forks {NoFork, Fork}
RoundTable =(Fork, Fork, Fork, Fork, Fork)
Getleft=lambda RoundTable (ph as philosopher) -> {
where=(ph+4) mod 5
= RoundTable#val(where)
Return RoundTable, where:=NoFork
}
GetRight=lambda RoundTable (ph as philosopher) -> {
where=ph mod 5
=RoundTable#val(where)
Return RoundTable, where:=NoFork
}
PlaceForks=lambda RoundTable (ph as philosopher) -> {
Return RoundTable, (ph+4) mod 5:=Fork, ph mod 5:=Fork
}
ShowTable=lambda RoundTable -> {
m=each(RoundTable)
while m
print if$(array(m)=NoFork->"No Fork", "Fork"),
end while
Print
}
noforks=lambda RoundTable -> {
k=0
m=each(RoundTable)
while m
if array(m)=NoFork then k++
end while
=k=5
}
 
dim a(5), eattimes(1 to 5)=0
def critical as long, basetick
Document page$
m=each(philosopher)
while m {
\\ we make 5 threads
\\ a thread has module scope (except for own static variables, and stack of values)
thread {
Page$=format$("{0::-12} - ",tick-basetick)+eval$(f)+if$(forkL=Nofork or forkR=Nofork->" thinking", " eating")+nl$
if not think then
{ \\ a block always run blocking all other threads
eattimes(f)++
Call PlaceForks(f) : forkL=Nofork:forkR=NoFork
think=true :thread this interval time_to_think*random(1,5)
}
else.if R then
if forkR=Nofork then forkR=GetRight(f)
if forkR=fork and forkL=Nofork then forkL=GetLeft(f)
if forkL=fork then think=false:thread this interval time_to_eat
else
if forkL=Nofork then forkL=GetLeft(f)
if forkL=fork and forkR=Nofork then forkR=GetRight(f)
if forkR=fork then think=false:thread this interval time_to_eat
end if
} as a interval time_to_appear#val(m^)
\\ a is a variable which hold the number of thread (as returned from task manager)
\\ so we can get 5 times a new number.
\\ for each thread we make some static variables (only for each thread)
\\ this statement execute a line of code in thread a
thread a execute static f=eval(m), think=true, forkL=NoFork, forkR=NoFork, R=Random(-1,0)
}
cls ,4 ' set split screen from fifth row
\\ Main.Task is a thread also. Normaly exit if no other threads running in background
\\ also serve a the wait loop for task manager (we can use Every 200 {} but isn't a thread, is a kind of a wait statement)
\\ tick return the counter from task manager which used to triger threads
basetick=tick
\\ 4hz display results
Main.Task 1000/4 {
{ \\ a block always run blocking all other threads
cls
Print $(1),eattimes()
Print $(0)
Print "Table:"
Call ShowTable()
if noforks() then critical++ else critical=0
Print "noforks on table counter:";critical
Print #-2,Page$
Doc$=Page$
Clear Page$
if critical>40 or keypress(1) then break
}
}
\\ because we can exit when some threads are alive, we can erase them now
threads erase
Clipboard Doc$
}
Dining_philosophers Random(1,2)
</lang>
 
{{out}}
<pre style="height:30ex;overflow:scroll">
Dining Philosophers
Sequential threads - to execute exclusive one threads code
1257 - Kant thinking
1258 - Spinoza thinking
1259 - Marx thinking
1260 - Russell thinking
2073 - Kant eating
2135 - Marx eating
2144 - Aristotle thinking
..................................
55163 - Marx eating
55455 - Kant thinking
56193 - Kant eating
56394 - Russell thinking
56812 - Spinoza thinking
57192 - Russell eating
57514 - Spinoza eating
59056 - Spinoza thinking
59060 - Aristotle thinking
 
Dining Philosophers
Concurrent threads - to execute a statement or a block of code
818 - Aristotle thinking
825 - Kant thinking
832 - Spinoza thinking
839 - Marx thinking
1610 - Aristotle thinking
1617 - Kant thinking
1618 - Spinoza thinking
1626 - Russell thinking
....................................
56585 - Marx eating
56744 - Aristotle eating
58311 - Kant thinking
59397 - Kant eating
60424 - Spinoza thinking
61468 - Spinoza eating
61974 - Russell thinking
</pre >
=={{header|Modula-3}}==
From this implementation's point of view, a "resource" is not a ''fork'', but rather a ''place at the table''. Rather than use one <code>MUTEX</code> for ''each'' fork, it uses one <code>MUTEX</code> for the entire table.
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.