Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
7
Task/Dining-philosophers/00-META.yaml
Normal file
7
Task/Dining-philosophers/00-META.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
category:
|
||||
- Classic CS problems and programs
|
||||
from: http://rosettacode.org/wiki/Dining_philosophers
|
||||
note: Concurrency
|
||||
requires:
|
||||
- Concurrency
|
||||
8
Task/Dining-philosophers/00-TASK.txt
Normal file
8
Task/Dining-philosophers/00-TASK.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
The dining philosophers problem illustrates non-composability of low-level synchronization primitives like [[semaphore]]s. It is a modification of a problem posed by [https://en.wikipedia.org/wiki/Edsger_W._Dijkstra Edsger Dijkstra.]
|
||||
|
||||
Five philosophers, Aristotle, Kant, Spinoza, Marx, and Russell (the [[task]]s) spend their time thinking and eating spaghetti. They eat at a round table with five individual seats. For eating each philosopher needs two forks (the resources). There are five forks on the table, one left and one right of each seat. When a philosopher cannot grab both forks it sits and waits. Eating takes random time, then the philosopher puts the forks down and leaves the dining room. After spending some random time thinking about the nature of the universe, he again becomes hungry, and the circle repeats itself.
|
||||
|
||||
It can be observed that a straightforward solution, when forks are implemented by [[semaphore]]s, is exposed to deadlock. There exist two deadlock states when all five philosophers are sitting at the table holding one fork each. One deadlock state is when each philosopher has grabbed the fork left of him, and another is when each has the fork on his right.
|
||||
|
||||
There are many solutions of the problem, program at least one, and explain how the deadlock is prevented.
|
||||
|
||||
50
Task/Dining-philosophers/Ada/dining-philosophers-1.ada
Normal file
50
Task/Dining-philosophers/Ada/dining-philosophers-1.ada
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;
|
||||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
|
||||
with Synchronization.Generic_Mutexes_Array;
|
||||
|
||||
procedure Test_Dining_Philosophers is
|
||||
type Philosopher is (Aristotle, Kant, Spinoza, Marx, Russel);
|
||||
package Fork_Arrays is new Synchronization.Generic_Mutexes_Array (Philosopher);
|
||||
use Fork_Arrays;
|
||||
|
||||
Life_Span : constant := 20; -- In his life a philosopher eats 20 times
|
||||
Forks : aliased Mutexes_Array; -- Forks for hungry philosophers
|
||||
|
||||
function Left_Of (Fork : Philosopher) return Philosopher is
|
||||
begin
|
||||
if Fork = Philosopher'First then
|
||||
return Philosopher'Last;
|
||||
else
|
||||
return Philosopher'Pred (Fork);
|
||||
end if;
|
||||
end Left_Of;
|
||||
|
||||
task type Person (ID : Philosopher);
|
||||
task body Person is
|
||||
Cutlery : aliased Mutexes_Set := ID or Left_Of (ID);
|
||||
Dice : Generator;
|
||||
begin
|
||||
Reset (Dice);
|
||||
for Life_Cycle in 1..Life_Span loop
|
||||
Put_Line (Philosopher'Image (ID) & " is thinking");
|
||||
delay Duration (Random (Dice) * 0.100);
|
||||
Put_Line (Philosopher'Image (ID) & " is hungry");
|
||||
declare
|
||||
Lock : Set_Holder (Forks'Access, Cutlery'Access);
|
||||
begin
|
||||
Put_Line (Philosopher'Image (ID) & " is eating");
|
||||
delay Duration (Random (Dice) * 0.100);
|
||||
end;
|
||||
end loop;
|
||||
Put_Line (Philosopher'Image (ID) & " is leaving");
|
||||
end Person;
|
||||
|
||||
Ph_1 : Person (Aristotle); -- Start philosophers
|
||||
Ph_2 : Person (Kant);
|
||||
Ph_3 : Person (Spinoza);
|
||||
Ph_4 : Person (Marx);
|
||||
Ph_5 : Person (Russel);
|
||||
begin
|
||||
null; -- Nothing to do in the main task, just sit and behold
|
||||
end Test_Dining_Philosophers;
|
||||
53
Task/Dining-philosophers/Ada/dining-philosophers-2.ada
Normal file
53
Task/Dining-philosophers/Ada/dining-philosophers-2.ada
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;
|
||||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
|
||||
procedure Test_Dining_Philosophers is
|
||||
type Philosopher is (Aristotle, Kant, Spinoza, Marx, Russel);
|
||||
protected type Fork is
|
||||
entry Grab;
|
||||
procedure Put_Down;
|
||||
private
|
||||
Seized : Boolean := False;
|
||||
end Fork;
|
||||
protected body Fork is
|
||||
entry Grab when not Seized is
|
||||
begin
|
||||
Seized := True;
|
||||
end Grab;
|
||||
procedure Put_Down is
|
||||
begin
|
||||
Seized := False;
|
||||
end Put_Down;
|
||||
end Fork;
|
||||
|
||||
Life_Span : constant := 20; -- In his life a philosopher eats 20 times
|
||||
|
||||
task type Person (ID : Philosopher; First, Second : not null access Fork);
|
||||
task body Person is
|
||||
Dice : Generator;
|
||||
begin
|
||||
Reset (Dice);
|
||||
for Life_Cycle in 1..Life_Span loop
|
||||
Put_Line (Philosopher'Image (ID) & " is thinking");
|
||||
delay Duration (Random (Dice) * 0.100);
|
||||
Put_Line (Philosopher'Image (ID) & " is hungry");
|
||||
First.Grab;
|
||||
Second.Grab;
|
||||
Put_Line (Philosopher'Image (ID) & " is eating");
|
||||
delay Duration (Random (Dice) * 0.100);
|
||||
Second.Put_Down;
|
||||
First.Put_Down;
|
||||
end loop;
|
||||
Put_Line (Philosopher'Image (ID) & " is leaving");
|
||||
end Person;
|
||||
|
||||
Forks : array (1..5) of aliased Fork; -- Forks for hungry philosophers
|
||||
-- Start philosophers
|
||||
Ph_1 : Person (Aristotle, Forks (1)'Access, Forks (2)'Access);
|
||||
Ph_2 : Person (Kant, Forks (2)'Access, Forks (3)'Access);
|
||||
Ph_3 : Person (Spinoza, Forks (3)'Access, Forks (4)'Access);
|
||||
Ph_4 : Person (Marx, Forks (4)'Access, Forks (5)'Access);
|
||||
Ph_5 : Person (Russel, Forks (1)'Access, Forks (5)'Access);
|
||||
begin
|
||||
null; -- Nothing to do in the main task, just sit and behold
|
||||
end Test_Dining_Philosophers;
|
||||
75
Task/Dining-philosophers/Ada/dining-philosophers-3.ada
Normal file
75
Task/Dining-philosophers/Ada/dining-philosophers-3.ada
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;
|
||||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
|
||||
procedure Test_Dining_Philosophers is
|
||||
type Philosopher is (Aristotle, Kant, Spinoza, Marx, Russel);
|
||||
|
||||
protected type Fork is
|
||||
entry Grab;
|
||||
procedure Put_Down;
|
||||
private
|
||||
Seized : Boolean := False;
|
||||
end Fork;
|
||||
|
||||
protected Host is
|
||||
entry Greet;
|
||||
procedure Farewell;
|
||||
private
|
||||
Guests : Natural := 0;
|
||||
end Host;
|
||||
|
||||
protected body Fork is
|
||||
entry Grab when not Seized is
|
||||
begin
|
||||
Seized := True;
|
||||
end Grab;
|
||||
procedure Put_Down is
|
||||
begin
|
||||
Seized := False;
|
||||
end Put_Down;
|
||||
end Fork;
|
||||
|
||||
protected body Host is
|
||||
entry Greet when Guests < 5 is
|
||||
begin
|
||||
Guests := Guests + 1;
|
||||
end Greet;
|
||||
procedure Farewell is
|
||||
begin
|
||||
Guests := Guests - 1;
|
||||
end Farewell;
|
||||
end Host;
|
||||
|
||||
Life_Span : constant := 20; -- In his life a philosopher eats 20 times
|
||||
|
||||
task type Person (ID : Philosopher; Left, Right : not null access Fork);
|
||||
task body Person is
|
||||
Dice : Generator;
|
||||
begin
|
||||
Reset (Dice);
|
||||
for Life_Cycle in 1..Life_Span loop
|
||||
Put_Line (Philosopher'Image (ID) & " is thinking");
|
||||
delay Duration (Random (Dice) * 0.100);
|
||||
Put_Line (Philosopher'Image (ID) & " is hungry");
|
||||
Host.Greet;
|
||||
Left.Grab;
|
||||
Right.Grab;
|
||||
Put_Line (Philosopher'Image (ID) & " is eating");
|
||||
delay Duration (Random (Dice) * 0.100);
|
||||
Left.Put_Down;
|
||||
Right.Put_Down;
|
||||
Host.Farewell;
|
||||
end loop;
|
||||
Put_Line (Philosopher'Image (ID) & " is leaving");
|
||||
end Person;
|
||||
|
||||
Forks : array (1..5) of aliased Fork; -- Forks for hungry philosophers
|
||||
-- Start philosophers
|
||||
Ph_1 : Person (Aristotle, Forks (1)'Access, Forks (2)'Access);
|
||||
Ph_2 : Person (Kant, Forks (2)'Access, Forks (3)'Access);
|
||||
Ph_3 : Person (Spinoza, Forks (3)'Access, Forks (4)'Access);
|
||||
Ph_4 : Person (Marx, Forks (4)'Access, Forks (5)'Access);
|
||||
Ph_5 : Person (Russel, Forks (5)'Access, Forks (1)'Access);
|
||||
begin
|
||||
null; -- Nothing to do in the main task, just sit and behold
|
||||
end Test_Dining_Philosophers;
|
||||
142
Task/Dining-philosophers/AutoHotkey/dining-philosophers.ahk
Normal file
142
Task/Dining-philosophers/AutoHotkey/dining-philosophers.ahk
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#Persistent
|
||||
SetWorkingDir, %A_ScriptDir%
|
||||
FileDelete, output.txt
|
||||
EnoughForks := 2 ; required forks to begin eating
|
||||
Fork1 := Fork2 := Fork3 := Fork4 := Fork5 := 1 ; fork supply per philosopher
|
||||
SetTimer, AristotleWaitForLeftFork
|
||||
SetTimer, KantWaitForLeftFork
|
||||
SetTimer, SpinozaWaitForLeftFork
|
||||
SetTimer, MarxWaitForLeftFork
|
||||
SetTimer, RussellWaitForLeftFork
|
||||
Return ;---------------------------------------------------------------
|
||||
|
||||
AristotleWaitForLeftFork:
|
||||
WaitForFork("Aristotle", "left", Fork1, Fork2, AristotleLeftForkCount, AristotleRightForkCount, AristotleWaitCount, EnoughForks)
|
||||
Return
|
||||
AristotleWaitForRightFork:
|
||||
WaitForFork("Aristotle", "right", Fork2, Fork1, AristotleRightForkCount, AristotleLeftForkCount, AristotleWaitCount, EnoughForks)
|
||||
Return
|
||||
AristotleFinishEating:
|
||||
ReturnForks("Aristotle", Fork1, Fork2, AristotleLeftForkCount, AristotleRightForkCount, EnoughForks)
|
||||
Return
|
||||
|
||||
KantWaitForLeftFork:
|
||||
WaitForFork("Kant", "left", Fork2, Fork3, KantLeftForkCount, KantRightForkCount, KantWaitCount, EnoughForks)
|
||||
Return
|
||||
KantWaitForRightFork:
|
||||
WaitForFork("Kant", "right", Fork3, Fork2, KantRightForkCount, KantLeftForkCount, KantWaitCount, EnoughForks)
|
||||
Return
|
||||
KantFinishEating:
|
||||
ReturnForks("Kant", Fork2, Fork3, KantLeftForkCount, KantRightForkCount, EnoughForks)
|
||||
Return
|
||||
|
||||
SpinozaWaitForLeftFork:
|
||||
WaitForFork("Spinoza", "left", Fork3, Fork4, SpinozaLeftForkCount, SpinozaRightForkCount, SpinozaWaitCount, EnoughForks)
|
||||
Return
|
||||
SpinozaWaitForRightFork:
|
||||
WaitForFork("Spinoza", "right", Fork4, Fork3, SpinozaRightForkCount, SpinozaLeftForkCount, SpinozaWaitCount, EnoughForks)
|
||||
Return
|
||||
SpinozaFinishEating:
|
||||
ReturnForks("Spinoza", Fork3, Fork4, SpinozaLeftForkCount, SpinozaRightForkCount, EnoughForks)
|
||||
Return
|
||||
|
||||
MarxWaitForLeftFork:
|
||||
WaitForFork("Marx", "left", Fork4, Fork5, MarxLeftForkCount, MarxRightForkCount, MarxWaitCount, EnoughForks)
|
||||
Return
|
||||
MarxWaitForRightFork:
|
||||
WaitForFork("Marx", "right", Fork5, Fork4, MarxRightForkCount, MarxLeftForkCount, MarxWaitCount, EnoughForks)
|
||||
Return
|
||||
MarxFinishEating:
|
||||
ReturnForks("Marx", Fork4, Fork5, MarxLeftForkCount, MarxRightForkCount, EnoughForks)
|
||||
Return
|
||||
|
||||
RussellWaitForLeftFork:
|
||||
WaitForFork("Russell", "left", Fork5, Fork1, RussellLeftForkCount, RussellRightForkCount, RussellWaitCount, EnoughForks)
|
||||
Return
|
||||
RussellWaitForRightFork:
|
||||
WaitForFork("Russell", "right", Fork1, Fork5, RussellRightForkCount, RussellLeftForkCount, RussellWaitCount, EnoughForks)
|
||||
Return
|
||||
RussellFinishEating:
|
||||
ReturnForks("Russell", Fork5, Fork1, RussellLeftForkCount, RussellRightForkCount, EnoughForks)
|
||||
Return
|
||||
|
||||
ReturnForks(Philosopher, ByRef ThisFork, ByRef OtherFork, ByRef CurrentThisForkCount, ByRef CurrentOtherForkCount, EnoughForks) {
|
||||
OutputDebug, %Philosopher% finishes eating.
|
||||
FileAppend, %Philosopher% finishes eating.`n,output.txt
|
||||
ThisFork += CurrentThisForkCount ; return this fork
|
||||
OtherFork += CurrentOtherForkCount ; return other fork
|
||||
CurrentThisForkCount := 0 ; release this fork
|
||||
CurrentOtherForkCount := 0 ; release other fork
|
||||
OutputDebug, %Philosopher% returns all forks.
|
||||
FileAppend, %Philosopher% returns all forks.`n,output.txt
|
||||
|
||||
; do something while resting
|
||||
|
||||
Random, Rand, 0, 1
|
||||
Rand := Rand ? "Left" : "Right"
|
||||
SetTimer, %Philosopher%WaitFor%Rand%Fork
|
||||
}
|
||||
|
||||
WaitForFork(Philosopher, This, ByRef ThisFork, ByRef OtherFork, ByRef CurrentThisForkCount, ByRef CurrentOtherForkCount, ByRef CurrentWaitCount, EnoughForks) {
|
||||
If This not in Left,Right
|
||||
Return Error
|
||||
Other := (This="right") ? "left" : "right"
|
||||
OutputDebug, %Philosopher% is hungry.
|
||||
FileAppend, %Philosopher% is hungry.`n,output.txt
|
||||
If (ThisFork) ; if this fork available
|
||||
{
|
||||
SetTimer, %Philosopher%WaitFor%This%Fork, Off
|
||||
CurrentWaitCount := 0
|
||||
ThisFork-- ; take this fork
|
||||
CurrentThisForkCount++ ; receive this fork
|
||||
OutputDebug, %Philosopher% grabs %This% fork.
|
||||
FileAppend, %Philosopher% grabs %This% fork.`n,output.txt
|
||||
If (CurrentThisForkCount + CurrentOtherForkCount = EnoughForks) ; if philosopher has enough forks
|
||||
{
|
||||
OutputDebug, %Philosopher% starts eating.
|
||||
FileAppend, %Philosopher% starts eating.`n,output.txt
|
||||
|
||||
; do something while eating
|
||||
|
||||
SetTimer, %Philosopher%FinishEating, -250
|
||||
}
|
||||
Else If (EnoughForks=2)
|
||||
{
|
||||
SetTimer, %Philosopher%WaitFor%Other%Fork
|
||||
}
|
||||
Else
|
||||
{
|
||||
Random, Rand, 0, 1
|
||||
Rand := Rand ? "Left" : "Right"
|
||||
SetTimer, %Philosopher%WaitFor%Rand%Fork
|
||||
}
|
||||
}
|
||||
Else If (CurrentOtherForkCount and CurrentWaitCount > 5) ; if we've been holding other fork too long
|
||||
{
|
||||
SetTimer, %Philosopher%WaitFor%This%Fork, Off
|
||||
CurrentWaitCount := 0
|
||||
OtherFork++ ; return other fork
|
||||
CurrentOtherForkCount-- ; release other fork
|
||||
OutputDebug, %Philosopher% drops %Other% fork.
|
||||
FileAppend, %Philosopher% drops %Other% fork.`n,output.txt
|
||||
Random, Rand, 0, 1
|
||||
Rand := Rand ? "Left" : "Right"
|
||||
SetTimer, %Philosopher%WaitFor%Rand%Fork
|
||||
}
|
||||
Else If (CurrentThisForkCount and CurrentWaitCount > 5) ; if we've been holding one of this fork too long
|
||||
{
|
||||
SetTimer, %Philosopher%WaitFor%This%Fork, Off
|
||||
CurrentWaitCount := 0
|
||||
ThisFork++ ; return other fork
|
||||
CurrentThisForkCount-- ; release other fork
|
||||
OutputDebug, %Philosopher% drops %This% fork.
|
||||
FileAppend, %Philosopher% drops %This% fork.`n,output.txt
|
||||
Random, Rand, 0, 1
|
||||
Rand := Rand ? "Left" : "Right"
|
||||
SetTimer, %Philosopher%WaitFor%Rand%Fork
|
||||
}
|
||||
Else
|
||||
{
|
||||
CurrentWaitCount++
|
||||
}
|
||||
}
|
||||
66
Task/Dining-philosophers/BBC-BASIC/dining-philosophers.basic
Normal file
66
Task/Dining-philosophers/BBC-BASIC/dining-philosophers.basic
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
INSTALL @lib$+"TIMERLIB"
|
||||
|
||||
nSeats% = 5
|
||||
DIM Name$(nSeats%-1), Fork%(nSeats%-1), tID%(nSeats%-1), Leftie%(nSeats%-1)
|
||||
|
||||
Name$() = "Aristotle", "Kant", "Spinoza", "Marx", "Russell"
|
||||
Fork%() = TRUE : REM All forks are initially on the table
|
||||
Leftie%(RND(nSeats%)-1) = TRUE : REM One philosopher is lefthanded
|
||||
|
||||
tID%(0) = FN_ontimer(10, PROCphilosopher0, 1)
|
||||
tID%(1) = FN_ontimer(10, PROCphilosopher1, 1)
|
||||
tID%(2) = FN_ontimer(10, PROCphilosopher2, 1)
|
||||
tID%(3) = FN_ontimer(10, PROCphilosopher3, 1)
|
||||
tID%(4) = FN_ontimer(10, PROCphilosopher4, 1)
|
||||
|
||||
ON CLOSE PROCcleanup : QUIT
|
||||
ON ERROR PRINT REPORT$ : PROCcleanup : END
|
||||
|
||||
DEF PROCphilosopher0 : PROCtask(0) : ENDPROC
|
||||
DEF PROCphilosopher1 : PROCtask(1) : ENDPROC
|
||||
DEF PROCphilosopher2 : PROCtask(2) : ENDPROC
|
||||
DEF PROCphilosopher3 : PROCtask(3) : ENDPROC
|
||||
DEF PROCphilosopher4 : PROCtask(4) : ENDPROC
|
||||
|
||||
REPEAT
|
||||
WAIT 0
|
||||
UNTIL FALSE
|
||||
END
|
||||
|
||||
DEF PROCtask(n%)
|
||||
PRIVATE state%(), lh%(), rh%()
|
||||
DIM state%(nSeats%-1), lh%(nSeats%-1), rh%(nSeats%-1)
|
||||
REM States: 0 = waiting for forks, > 0 = eating, < 0 = left the room
|
||||
CASE TRUE OF
|
||||
WHEN state%(n%) < 0:
|
||||
state%(n%) += 1 : REM Waiting to get hungry again
|
||||
IF state%(n%) = 0 PRINT Name$(n%) " is hungry again"
|
||||
WHEN state%(n%) > 0:
|
||||
state%(n%) -= 1 : REM Eating
|
||||
IF state%(n%) = 0 THEN
|
||||
SWAP Fork%((n%-1+nSeats%) MOD nSeats%), lh%(n%)
|
||||
SWAP Fork%((n% + 1) MOD nSeats%), rh%(n%)
|
||||
state%(n%) = -RND(100)
|
||||
PRINT Name$(n%) " is leaving the room"
|
||||
ENDIF
|
||||
WHEN state%(n%) = 0:
|
||||
IF Leftie%(n%) THEN
|
||||
IF NOT lh%(n%) SWAP Fork%((n%-1+nSeats%) MOD nSeats%), lh%(n%)
|
||||
IF lh%(n%) IF NOT rh%(n%) SWAP Fork%((n% + 1) MOD nSeats%), rh%(n%)
|
||||
ELSE
|
||||
IF NOT rh%(n%) SWAP Fork%((n% + 1) MOD nSeats%), rh%(n%)
|
||||
IF rh%(n%) IF NOT lh%(n%) SWAP Fork%((n%-1+nSeats%) MOD nSeats%), lh%(n%)
|
||||
ENDIF
|
||||
IF lh%(n%) AND rh%(n%) THEN
|
||||
state%(n%) = RND(100)
|
||||
PRINT Name$(n%) " is eating (" ; state%(n%) " ticks)"
|
||||
ENDIF
|
||||
ENDCASE
|
||||
ENDPROC
|
||||
|
||||
DEF PROCcleanup
|
||||
LOCAL I%
|
||||
FOR I% = 0 TO nSeats%-1
|
||||
PROC_killtimer(tID%(I%))
|
||||
NEXT
|
||||
ENDPROC
|
||||
126
Task/Dining-philosophers/C++/dining-philosophers-1.cpp
Normal file
126
Task/Dining-philosophers/C++/dining-philosophers-1.cpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
|
||||
const int timeScale = 42; // scale factor for the philosophers task duration
|
||||
|
||||
void Message(std::string_view message)
|
||||
{
|
||||
// thread safe printing
|
||||
static std::mutex cout_mutex;
|
||||
std::scoped_lock cout_lock(cout_mutex);
|
||||
std::cout << message << std::endl;
|
||||
}
|
||||
|
||||
struct Fork {
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
struct Dinner {
|
||||
std::array<Fork, 5> forks;
|
||||
~Dinner() { Message("Dinner is over"); }
|
||||
};
|
||||
|
||||
class Philosopher
|
||||
{
|
||||
// generates random numbers using the Mersenne Twister algorithm
|
||||
// for task times and messages
|
||||
std::mt19937 rng{std::random_device {}()};
|
||||
|
||||
const std::string name;
|
||||
Fork& left;
|
||||
Fork& right;
|
||||
std::thread worker;
|
||||
|
||||
void live();
|
||||
void dine();
|
||||
void ponder();
|
||||
public:
|
||||
Philosopher(std::string name_, Fork& l, Fork& r)
|
||||
: name(std::move(name_)), left(l), right(r), worker(&Philosopher::live, this)
|
||||
{}
|
||||
~Philosopher()
|
||||
{
|
||||
worker.join();
|
||||
Message(name + " went to sleep.");
|
||||
}
|
||||
};
|
||||
|
||||
void Philosopher::live()
|
||||
{
|
||||
for(;;) // run forever
|
||||
{
|
||||
{
|
||||
//Aquire forks. scoped_lock acquires the mutexes for
|
||||
//both forks using a deadlock avoidance algorithm
|
||||
std::scoped_lock dine_lock(left.mutex, right.mutex);
|
||||
|
||||
dine();
|
||||
|
||||
//The mutexes are released here at the end of the scope
|
||||
}
|
||||
|
||||
ponder();
|
||||
}
|
||||
}
|
||||
|
||||
void Philosopher::dine()
|
||||
{
|
||||
Message(name + " started eating.");
|
||||
|
||||
// Print some random messages while the philosopher is eating
|
||||
thread_local std::array<const char*, 3> foods {"chicken", "rice", "soda"};
|
||||
thread_local std::array<const char*, 3> reactions {
|
||||
"I like this %s!", "This %s is good.", "Mmm, %s..."
|
||||
};
|
||||
thread_local std::uniform_int_distribution<> dist(1, 6);
|
||||
std::shuffle( foods.begin(), foods.end(), rng);
|
||||
std::shuffle(reactions.begin(), reactions.end(), rng);
|
||||
|
||||
constexpr size_t buf_size = 64;
|
||||
char buffer[buf_size];
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng) * timeScale));
|
||||
snprintf(buffer, buf_size, reactions[i], foods[i]);
|
||||
Message(name + ": " + buffer);
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng)) * timeScale);
|
||||
|
||||
Message(name + " finished and left.");
|
||||
}
|
||||
|
||||
void Philosopher::ponder()
|
||||
{
|
||||
static constexpr std::array<const char*, 5> topics {{
|
||||
"politics", "art", "meaning of life", "source of morality", "how many straws makes a bale"
|
||||
}};
|
||||
thread_local std::uniform_int_distribution<> wait(1, 6);
|
||||
thread_local std::uniform_int_distribution<> dist(0, topics.size() - 1);
|
||||
while(dist(rng) > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(wait(rng) * 3 * timeScale));
|
||||
Message(name + " is pondering about " + topics[dist(rng)] + ".");
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(wait(rng) * 3 * timeScale));
|
||||
Message(name + " is hungry again!");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Dinner dinner;
|
||||
Message("Dinner started!");
|
||||
// The philosophers will start as soon as they are created
|
||||
std::array<Philosopher, 5> philosophers {{
|
||||
{"Aristotle", dinner.forks[0], dinner.forks[1]},
|
||||
{"Democritus", dinner.forks[1], dinner.forks[2]},
|
||||
{"Plato", dinner.forks[2], dinner.forks[3]},
|
||||
{"Pythagoras", dinner.forks[3], dinner.forks[4]},
|
||||
{"Socrates", dinner.forks[4], dinner.forks[0]},
|
||||
}};
|
||||
Message("It is dark outside...");
|
||||
}
|
||||
226
Task/Dining-philosophers/C++/dining-philosophers-2.cpp
Normal file
226
Task/Dining-philosophers/C++/dining-philosophers-2.cpp
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Fork {
|
||||
static const int ON_TABLE = -1;
|
||||
int holder = ON_TABLE;
|
||||
int request = ON_TABLE;
|
||||
int id;
|
||||
bool dirty = true;
|
||||
Fork(int id) {
|
||||
this->id = id;
|
||||
}
|
||||
bool isRequest() {
|
||||
return request != Fork::ON_TABLE;
|
||||
}
|
||||
|
||||
void process(int &forkCount, int &dirtyCount) {
|
||||
if (holder == id) {
|
||||
forkCount++;
|
||||
if (isRequest()) {
|
||||
if (dirty) {
|
||||
forkCount--;
|
||||
dirty = false;
|
||||
holder = request;
|
||||
}
|
||||
request = Fork::ON_TABLE;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (holder == Fork::ON_TABLE) {
|
||||
holder = id;
|
||||
forkCount++;
|
||||
assert(dirty);
|
||||
dirtyCount++;
|
||||
assert(request == Fork::ON_TABLE);
|
||||
} else {
|
||||
request = id;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Table;
|
||||
|
||||
enum State { Have0Forks, Have1Fork,Have01Fork, Have2Forks, Eat, AfterEat, Pon };
|
||||
|
||||
class Philosopher {
|
||||
int id;
|
||||
Table *table;
|
||||
public:
|
||||
Fork* left;
|
||||
Fork* right;
|
||||
int eatStarts = 0;
|
||||
Philosopher(Table *table, int id);
|
||||
void naive();
|
||||
void ChandyMisra();
|
||||
State state;
|
||||
|
||||
void selectState(int forkCount, int dirtyCount);
|
||||
};
|
||||
|
||||
class Table {
|
||||
mt19937 mt_rand;
|
||||
std::uniform_real_distribution<> dis;
|
||||
unique_ptr<std::uniform_int_distribution<>> disint;
|
||||
public:
|
||||
static const int PhilCount = 5;
|
||||
vector<unique_ptr<Philosopher>> philosophers;
|
||||
vector<unique_ptr<Fork>> forks;
|
||||
Table() {
|
||||
mt_rand.seed(1234);
|
||||
disint = make_unique<std::uniform_int_distribution<>>(0, PhilCount-1);
|
||||
for (int i=0; i<PhilCount; i++)
|
||||
forks.push_back(make_unique<Fork>(i));
|
||||
for (int i=0; i<PhilCount; i++)
|
||||
philosophers.push_back(make_unique<Philosopher>(this, i));
|
||||
}
|
||||
double rand() {
|
||||
return dis(mt_rand);
|
||||
}
|
||||
|
||||
double randInt() {
|
||||
return (*disint)(mt_rand);
|
||||
}
|
||||
void naive() {
|
||||
cout << "Naive algorithm" << endl;
|
||||
for (int i=0; i<Table::PhilCount; i++)
|
||||
philosophers[i]->state = State::Have0Forks;
|
||||
for (int i=0; i<100000; i++) {
|
||||
philosophers[randInt()]->naive();
|
||||
}
|
||||
for (int i=0; i<Table::PhilCount; i++)
|
||||
cout << i << " : " << philosophers[i]->eatStarts << endl;
|
||||
}
|
||||
void ChandyMisra() {
|
||||
cout << "Chandy-Misra algorithm" << endl;
|
||||
for (int i=0; i<Table::PhilCount; i++) {
|
||||
philosophers[i]->state = State::Have01Fork;
|
||||
philosophers[i]->eatStarts = 0;
|
||||
philosophers[i]->left->holder = i;
|
||||
}
|
||||
for (int i=0; i<100000; i++) {
|
||||
philosophers[randInt()]->ChandyMisra();
|
||||
}
|
||||
for (int i=0; i<Table::PhilCount; i++)
|
||||
cout << i << " : " << philosophers[i]->eatStarts << endl;
|
||||
}
|
||||
};
|
||||
|
||||
Philosopher::Philosopher(Table *table, int id):table(table), id(id) {
|
||||
left = table->forks[id].get();
|
||||
right = table->forks[(id+1) % Table::PhilCount].get();
|
||||
}
|
||||
|
||||
void Philosopher::naive() {
|
||||
switch (state) {
|
||||
case State::Pon:
|
||||
if (table->rand()<0.2)
|
||||
state = State::Have0Forks;
|
||||
return;
|
||||
case State::Have0Forks:
|
||||
int forkCount;
|
||||
forkCount = 0;
|
||||
if (left->holder==Fork::ON_TABLE) {
|
||||
left->holder=id;
|
||||
forkCount++;
|
||||
}
|
||||
if (right->holder==Fork::ON_TABLE) {
|
||||
right->holder=id;
|
||||
forkCount++;
|
||||
}
|
||||
if (forkCount==1)
|
||||
state = State::Have1Fork;
|
||||
else if (forkCount==2)
|
||||
state = State::Have2Forks;
|
||||
return;
|
||||
case State::Have1Fork:
|
||||
Fork* forkToWait;
|
||||
if (left->holder==id)
|
||||
forkToWait = right;
|
||||
else
|
||||
forkToWait = left;
|
||||
if (forkToWait->holder==Fork::ON_TABLE) {
|
||||
forkToWait->holder=id;
|
||||
state = State::Have2Forks;
|
||||
}
|
||||
return;
|
||||
case State::Have2Forks:
|
||||
state = State::Eat;
|
||||
eatStarts++;
|
||||
return;
|
||||
case State::Eat:
|
||||
if (table->rand()<0.2)
|
||||
state = State::AfterEat;
|
||||
return;
|
||||
case State::AfterEat:
|
||||
left->holder = Fork::ON_TABLE;
|
||||
right->holder = Fork::ON_TABLE;
|
||||
state = State::Pon;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Philosopher::ChandyMisra() {
|
||||
switch (state) {
|
||||
case State::Pon:
|
||||
if (table->rand() < 0.2)
|
||||
state = State::Have01Fork;
|
||||
return;
|
||||
case State::Have01Fork:
|
||||
int forkCount;
|
||||
int dirtyCount;
|
||||
forkCount = 0;
|
||||
dirtyCount = 0;
|
||||
left->process(forkCount, dirtyCount);
|
||||
right->process(forkCount, dirtyCount);
|
||||
selectState(forkCount, dirtyCount);
|
||||
return;
|
||||
case State::Have2Forks:
|
||||
state = State::Eat;
|
||||
eatStarts++;
|
||||
return;
|
||||
case State::Eat:
|
||||
if (table->rand()<0.2)
|
||||
state = State::AfterEat;
|
||||
return;
|
||||
case State::AfterEat:
|
||||
if (left->request!=Fork::ON_TABLE) {
|
||||
left->dirty = false;
|
||||
left->holder = left->request;
|
||||
left->request = Fork::ON_TABLE;
|
||||
} else {
|
||||
left->holder = Fork::ON_TABLE;
|
||||
left->dirty = true;
|
||||
}
|
||||
|
||||
if (right->request!=Fork::ON_TABLE) {
|
||||
right->dirty = false;
|
||||
right->holder = right->request;
|
||||
right->request = Fork::ON_TABLE;
|
||||
} else {
|
||||
right->holder = Fork::ON_TABLE;
|
||||
right->dirty = true;
|
||||
}
|
||||
state = State::Pon;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Philosopher::selectState(int forkCount, int dirtyCount) {
|
||||
if (forkCount == 2 && dirtyCount==0)
|
||||
state = State::Have2Forks;
|
||||
else
|
||||
state = State::Have01Fork;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Table table;
|
||||
table.naive();
|
||||
table.ChandyMisra();
|
||||
return 0;
|
||||
}
|
||||
248
Task/Dining-philosophers/C-sharp/dining-philosophers.cs
Normal file
248
Task/Dining-philosophers/C-sharp/dining-philosophers.cs
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dining_Philosophers
|
||||
{
|
||||
class Program
|
||||
{
|
||||
private const int DinerCount = 5;
|
||||
private static List<Diner> Diners = new List<Diner>();
|
||||
private static List<Fork> Forks = new List<Fork>();
|
||||
private static DateTime TimeToStop;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Initialize();
|
||||
WriteHeaderLine();
|
||||
|
||||
do
|
||||
{
|
||||
WriteStatusLine();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
while (DateTime.Now < TimeToStop);
|
||||
|
||||
TearDown();
|
||||
}
|
||||
|
||||
private static void Initialize()
|
||||
{
|
||||
for (int i = 0; i < DinerCount; i++)
|
||||
Forks.Add(new Fork());
|
||||
for (int i = 0; i < DinerCount; i++)
|
||||
Diners.Add(new Diner(i, Forks[i], Forks[(i + 1) % DinerCount]));
|
||||
|
||||
TimeToStop = DateTime.Now.AddSeconds(60);
|
||||
}
|
||||
|
||||
private static void TearDown()
|
||||
{
|
||||
foreach (var diner in Diners)
|
||||
diner.Dispose();
|
||||
}
|
||||
|
||||
private static void WriteHeaderLine()
|
||||
{
|
||||
Console.Write("|");
|
||||
|
||||
foreach (Diner d in Diners)
|
||||
Console.Write("D " + d.ID + "|");
|
||||
|
||||
Console.Write(" |");
|
||||
|
||||
for (int i = 0; i < DinerCount; i++)
|
||||
Console.Write("F" + i + "|");
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static void WriteStatusLine()
|
||||
{
|
||||
Console.Write("|");
|
||||
|
||||
foreach (Diner d in Diners)
|
||||
Console.Write(FormatDinerState(d) + "|");
|
||||
|
||||
Console.Write(" |");
|
||||
|
||||
foreach (Fork f in Forks)
|
||||
Console.Write(FormatForkState(f) + "|");
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static string FormatDinerState(Diner diner)
|
||||
{
|
||||
switch (diner.State)
|
||||
{
|
||||
case Diner.DinerState.Eating:
|
||||
return "Eat";
|
||||
case Diner.DinerState.Pondering:
|
||||
return "Pon";
|
||||
case Diner.DinerState.TryingToGetForks:
|
||||
return "Get";
|
||||
default:
|
||||
throw new Exception("Unknown diner state.");
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatForkState(Fork fork)
|
||||
{
|
||||
return (!ForkIsBeingUsed(fork) ? " " : "D" + GetForkHolder(fork));
|
||||
}
|
||||
|
||||
private static bool ForkIsBeingUsed(Fork fork)
|
||||
{
|
||||
return Diners.Count(d => d.CurrentlyHeldForks.Contains(fork)) > 0;
|
||||
}
|
||||
|
||||
private static int GetForkHolder(Fork fork)
|
||||
{
|
||||
return Diners.Single(d => d.CurrentlyHeldForks.Contains(fork)).ID;
|
||||
}
|
||||
}
|
||||
|
||||
class Diner : IDisposable
|
||||
{
|
||||
private bool IsCurrentlyHoldingLeftFork = false;
|
||||
private bool IsCurrentlyHoldingRightFork = false;
|
||||
private const int MaximumWaitTime = 100;
|
||||
private static Random Randomizer = new Random();
|
||||
private bool ShouldStopEating = false;
|
||||
|
||||
public int ID { get; private set; }
|
||||
public Fork LeftFork { get; private set; }
|
||||
public Fork RightFork { get; private set; }
|
||||
public DinerState State { get; private set; }
|
||||
|
||||
public IEnumerable<Fork> CurrentlyHeldForks
|
||||
{
|
||||
get
|
||||
{
|
||||
var forks = new List<Fork>();
|
||||
if (IsCurrentlyHoldingLeftFork)
|
||||
forks.Add(LeftFork);
|
||||
if (IsCurrentlyHoldingRightFork)
|
||||
forks.Add(RightFork);
|
||||
return forks;
|
||||
}
|
||||
}
|
||||
|
||||
public Diner(int id, Fork leftFork, Fork rightFork)
|
||||
{
|
||||
InitializeDinerState(id, leftFork, rightFork);
|
||||
BeginDinerActivity();
|
||||
}
|
||||
|
||||
private void KeepTryingToEat()
|
||||
{
|
||||
do
|
||||
if (State == DinerState.TryingToGetForks)
|
||||
{
|
||||
TryToGetLeftFork();
|
||||
if (IsCurrentlyHoldingLeftFork)
|
||||
{
|
||||
TryToGetRightFork();
|
||||
if (IsCurrentlyHoldingRightFork)
|
||||
{
|
||||
Eat();
|
||||
DropForks();
|
||||
Ponder();
|
||||
}
|
||||
else
|
||||
{
|
||||
DropForks();
|
||||
WaitForAMoment();
|
||||
}
|
||||
}
|
||||
else
|
||||
WaitForAMoment();
|
||||
}
|
||||
else
|
||||
State = DinerState.TryingToGetForks;
|
||||
while (!ShouldStopEating);
|
||||
}
|
||||
|
||||
private void InitializeDinerState(int id, Fork leftFork, Fork rightFork)
|
||||
{
|
||||
ID = id;
|
||||
LeftFork = leftFork;
|
||||
RightFork = rightFork;
|
||||
State = DinerState.TryingToGetForks;
|
||||
}
|
||||
|
||||
private async void BeginDinerActivity()
|
||||
{
|
||||
await Task.Run(() => KeepTryingToEat());
|
||||
}
|
||||
|
||||
private void TryToGetLeftFork()
|
||||
{
|
||||
Monitor.TryEnter(LeftFork, ref IsCurrentlyHoldingLeftFork);
|
||||
}
|
||||
|
||||
private void TryToGetRightFork()
|
||||
{
|
||||
Monitor.TryEnter(RightFork, ref IsCurrentlyHoldingRightFork);
|
||||
}
|
||||
|
||||
private void DropForks()
|
||||
{
|
||||
DropLeftFork();
|
||||
DropRightFork();
|
||||
}
|
||||
|
||||
private void DropLeftFork()
|
||||
{
|
||||
if (IsCurrentlyHoldingLeftFork)
|
||||
{
|
||||
IsCurrentlyHoldingLeftFork = false;
|
||||
Monitor.Exit(LeftFork);
|
||||
}
|
||||
}
|
||||
|
||||
private void DropRightFork()
|
||||
{
|
||||
if (IsCurrentlyHoldingRightFork)
|
||||
{
|
||||
IsCurrentlyHoldingRightFork = false;
|
||||
Monitor.Exit(RightFork);
|
||||
}
|
||||
}
|
||||
|
||||
private void Eat()
|
||||
{
|
||||
State = DinerState.Eating;
|
||||
WaitForAMoment();
|
||||
}
|
||||
|
||||
private void Ponder()
|
||||
{
|
||||
State = DinerState.Pondering;
|
||||
WaitForAMoment();
|
||||
}
|
||||
|
||||
private static void WaitForAMoment()
|
||||
{
|
||||
Thread.Sleep(Randomizer.Next(MaximumWaitTime));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ShouldStopEating = true;
|
||||
}
|
||||
|
||||
public enum DinerState
|
||||
{
|
||||
Eating,
|
||||
TryingToGetForks,
|
||||
Pondering
|
||||
}
|
||||
}
|
||||
|
||||
class Fork { }
|
||||
}
|
||||
95
Task/Dining-philosophers/C/dining-philosophers-1.c
Normal file
95
Task/Dining-philosophers/C/dining-philosophers-1.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define N 5
|
||||
const char *names[N] = { "Aristotle", "Kant", "Spinoza", "Marx", "Russell" };
|
||||
pthread_mutex_t forks[N];
|
||||
|
||||
#define M 5 /* think bubbles */
|
||||
const char *topic[M] = { "Spaghetti!", "Life", "Universe", "Everything", "Bathroom" };
|
||||
|
||||
#define lock pthread_mutex_lock
|
||||
#define unlock pthread_mutex_unlock
|
||||
#define xy(x, y) printf("\033[%d;%dH", x, y)
|
||||
#define clear_eol(x) print(x, 12, "\033[K")
|
||||
void print(int y, int x, const char *fmt, ...)
|
||||
{
|
||||
static pthread_mutex_t screen = PTHREAD_MUTEX_INITIALIZER;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
lock(&screen);
|
||||
xy(y + 1, x), vprintf(fmt, ap);
|
||||
xy(N + 1, 1), fflush(stdout);
|
||||
unlock(&screen);
|
||||
}
|
||||
|
||||
void eat(int id)
|
||||
{
|
||||
int f[2], ration, i; /* forks */
|
||||
f[0] = f[1] = id;
|
||||
|
||||
/* make some (but not all) philosophers leftie.
|
||||
could have been f[!id] = (id + 1) %N; for example */
|
||||
f[id & 1] = (id + 1) % N;
|
||||
|
||||
clear_eol(id);
|
||||
print(id, 12, "..oO (forks, need forks)");
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
lock(forks + f[i]);
|
||||
if (!i) clear_eol(id);
|
||||
|
||||
print(id, 12 + (f[i] != id) * 6, "fork%d", f[i]);
|
||||
/* delay 1 sec to clearly show the order of fork acquisition */
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
for (i = 0, ration = 3 + rand() % 8; i < ration; i++)
|
||||
print(id, 24 + i * 4, "nom"), sleep(1);
|
||||
|
||||
/* done nomming, give up forks (order doesn't matter) */
|
||||
for (i = 0; i < 2; i++) unlock(forks + f[i]);
|
||||
}
|
||||
|
||||
void think(int id)
|
||||
{
|
||||
int i, t;
|
||||
char buf[64] = {0};
|
||||
|
||||
do {
|
||||
clear_eol(id);
|
||||
sprintf(buf, "..oO (%s)", topic[t = rand() % M]);
|
||||
|
||||
for (i = 0; buf[i]; i++) {
|
||||
print(id, i+12, "%c", buf[i]);
|
||||
if (i < 5) usleep(200000);
|
||||
}
|
||||
usleep(500000 + rand() % 1000000);
|
||||
} while (t);
|
||||
}
|
||||
|
||||
void* philosophize(void *a)
|
||||
{
|
||||
int id = *(int*)a;
|
||||
print(id, 1, "%10s", names[id]);
|
||||
while(1) think(id), eat(id);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i, id[N];
|
||||
pthread_t tid[N];
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
pthread_mutex_init(forks + (id[i] = i), 0);
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
pthread_create(tid + i, 0, philosophize, id + i);
|
||||
|
||||
/* wait forever: the threads don't actually stop */
|
||||
return pthread_join(tid[0], 0);
|
||||
}
|
||||
94
Task/Dining-philosophers/C/dining-philosophers-2.c
Normal file
94
Task/Dining-philosophers/C/dining-philosophers-2.c
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct philData {
|
||||
pthread_mutex_t *fork_lft, *fork_rgt;
|
||||
const char *name;
|
||||
pthread_t thread;
|
||||
int fail;
|
||||
} Philosopher;
|
||||
|
||||
int running = 1;
|
||||
|
||||
void *PhilPhunction(void *p) {
|
||||
Philosopher *phil = (Philosopher*)p;
|
||||
int failed;
|
||||
int tries_left;
|
||||
pthread_mutex_t *fork_lft, *fork_rgt, *fork_tmp;
|
||||
|
||||
while (running) {
|
||||
printf("%s is sleeping --er thinking\n", phil->name);
|
||||
sleep( 1+ rand()%8);
|
||||
|
||||
fork_lft = phil->fork_lft;
|
||||
fork_rgt = phil->fork_rgt;
|
||||
printf("%s is hungry\n", phil->name);
|
||||
tries_left = 2; /* try twice before being forceful */
|
||||
do {
|
||||
failed = pthread_mutex_lock( fork_lft);
|
||||
failed = (tries_left>0)? pthread_mutex_trylock( fork_rgt )
|
||||
: pthread_mutex_lock(fork_rgt);
|
||||
if (failed) {
|
||||
pthread_mutex_unlock( fork_lft);
|
||||
fork_tmp = fork_lft;
|
||||
fork_lft = fork_rgt;
|
||||
fork_rgt = fork_tmp;
|
||||
tries_left -= 1;
|
||||
}
|
||||
} while(failed && running);
|
||||
|
||||
if (!failed) {
|
||||
printf("%s is eating\n", phil->name);
|
||||
sleep( 1+ rand() % 8);
|
||||
pthread_mutex_unlock( fork_rgt);
|
||||
pthread_mutex_unlock( fork_lft);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Ponder()
|
||||
{
|
||||
const char *nameList[] = { "Kant", "Guatma", "Russel", "Aristotle", "Bart" };
|
||||
pthread_mutex_t forks[5];
|
||||
Philosopher philosophers[5];
|
||||
Philosopher *phil;
|
||||
int i;
|
||||
int failed;
|
||||
|
||||
for (i=0;i<5; i++) {
|
||||
failed = pthread_mutex_init(&forks[i], NULL);
|
||||
if (failed) {
|
||||
printf("Failed to initialize mutexes.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<5; i++) {
|
||||
phil = &philosophers[i];
|
||||
phil->name = nameList[i];
|
||||
phil->fork_lft = &forks[i];
|
||||
phil->fork_rgt = &forks[(i+1)%5];
|
||||
phil->fail = pthread_create( &phil->thread, NULL, PhilPhunction, phil);
|
||||
}
|
||||
|
||||
sleep(40);
|
||||
running = 0;
|
||||
printf("cleanup time\n");
|
||||
|
||||
for(i=0; i<5; i++) {
|
||||
phil = &philosophers[i];
|
||||
if ( !phil->fail && pthread_join( phil->thread, NULL) ) {
|
||||
printf("error joining thread for %s", phil->name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Ponder();
|
||||
return 0;
|
||||
}
|
||||
60
Task/Dining-philosophers/C/dining-philosophers-3.c
Normal file
60
Task/Dining-philosophers/C/dining-philosophers-3.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#include <stdio.h>
|
||||
#include <threads.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NUM_THREADS 5
|
||||
|
||||
struct timespec time1;
|
||||
mtx_t forks[NUM_THREADS];
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int left;
|
||||
int right;
|
||||
} Philosopher;
|
||||
|
||||
Philosopher *create(char *nam, int lef, int righ) {
|
||||
Philosopher *x = malloc(sizeof(Philosopher));
|
||||
x->name = nam;
|
||||
x->left = lef;
|
||||
x->right = righ;
|
||||
return x;
|
||||
}
|
||||
|
||||
int eat(void *data) {
|
||||
time1.tv_sec = 1;
|
||||
Philosopher *foo = (Philosopher *) data;
|
||||
mtx_lock(&forks[foo->left]);
|
||||
mtx_lock(&forks[foo->right]);
|
||||
printf("%s is eating\n", foo->name);
|
||||
thrd_sleep(&time1, NULL);
|
||||
printf("%s is done eating\n", foo->name);
|
||||
mtx_unlock(&forks[foo->left]);
|
||||
mtx_unlock(&forks[foo->right]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
thrd_t threadId[NUM_THREADS];
|
||||
Philosopher *all[NUM_THREADS] = {create("Teral", 0 ,1),
|
||||
create("Billy", 1, 2),
|
||||
create("Daniel", 2,3),
|
||||
create("Philip", 3, 4),
|
||||
create("Bennet", 0, 4)};
|
||||
for (int i = 0; i < NUM_THREADS; i++){
|
||||
if (mtx_init(&forks[i], mtx_plain) != thrd_success){
|
||||
puts("FAILED IN MUTEX INIT!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (int i=0; i < NUM_THREADS; ++i) {
|
||||
if (thrd_create(threadId+i, eat, all[i]) != thrd_success) {
|
||||
printf("%d-th thread create error\n", i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i < NUM_THREADS; ++i)
|
||||
thrd_join(threadId[i], NULL);
|
||||
return 0;
|
||||
}
|
||||
30
Task/Dining-philosophers/Clojure/dining-philosophers-1.clj
Normal file
30
Task/Dining-philosophers/Clojure/dining-philosophers-1.clj
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
(defn make-fork []
|
||||
(ref true))
|
||||
|
||||
(defn make-philosopher [name forks food-amt]
|
||||
(ref {:name name :forks forks :eating? false :food food-amt}))
|
||||
|
||||
(defn start-eating [phil]
|
||||
(dosync
|
||||
(if (every? true? (map ensure (:forks @phil))) ; <-- the essential solution
|
||||
(do
|
||||
(doseq [f (:forks @phil)] (alter f not))
|
||||
(alter phil assoc :eating? true)
|
||||
(alter phil update-in [:food] dec)
|
||||
true)
|
||||
false)))
|
||||
|
||||
(defn stop-eating [phil]
|
||||
(dosync
|
||||
(when (:eating? @phil)
|
||||
(alter phil assoc :eating? false)
|
||||
(doseq [f (:forks @phil)] (alter f not)))))
|
||||
|
||||
(defn dine [phil retry-interval max-eat-duration max-think-duration]
|
||||
(while (pos? (:food @phil))
|
||||
(if (start-eating phil)
|
||||
(do
|
||||
(Thread/sleep (rand-int max-eat-duration))
|
||||
(stop-eating phil)
|
||||
(Thread/sleep (rand-int max-think-duration)))
|
||||
(Thread/sleep retry-interval))))
|
||||
20
Task/Dining-philosophers/Clojure/dining-philosophers-2.clj
Normal file
20
Task/Dining-philosophers/Clojure/dining-philosophers-2.clj
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
(def *forks* (cycle (take 5 (repeatedly #(make-fork)))))
|
||||
|
||||
(def *philosophers*
|
||||
(doall (map #(make-philosopher %1 [(nth *forks* %2) (nth *forks* (inc %2))] 1000)
|
||||
["Aristotle" "Kant" "Spinoza" "Marx" "Russell"]
|
||||
(range 5))))
|
||||
|
||||
(defn start []
|
||||
(doseq [phil *philosophers*]
|
||||
(.start (Thread. #(dine phil 5 100 100)))))
|
||||
|
||||
(defn status []
|
||||
(dosync
|
||||
(doseq [i (range 5)]
|
||||
(let [f @(nth *forks* i)
|
||||
p @(nth *philosophers* i)]
|
||||
(println (str "fork: available=" f))
|
||||
(println (str (:name p)
|
||||
": eating=" (:eating? p)
|
||||
" food=" (:food p)))))))
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
(in-package :common-lisp-user)
|
||||
|
||||
;;
|
||||
;; FLAG -- if using quicklisp, you can get bordeaux-threads loaded up
|
||||
;; with: (ql:quickload :bordeaux-threads)
|
||||
;;
|
||||
|
||||
(defvar *philosophers* '(Aristotle Kant Spinoza Marx Russell))
|
||||
|
||||
(defclass philosopher ()
|
||||
((name :initarg :name :reader name-of)
|
||||
(left-fork :initarg :left-fork :accessor left-fork-of)
|
||||
(right-fork :initarg :right-fork :accessor right-fork-of)
|
||||
(meals-left :initarg :meals-left :accessor meals-left-of)))
|
||||
|
||||
(defclass fork ()
|
||||
((lock :initform (bt:make-lock "fork") :reader lock-of)))
|
||||
|
||||
(defun random-normal (&optional (mean 0.0) (sd 1.0))
|
||||
(do* ((x1 #1=(1- (* 2.0d0 (random 1d0))) #1#)
|
||||
(x2 #2=(1- (* 2.0d0 (random 1d0))) #2#)
|
||||
(w #3=(+ (* x1 x1) (* x2 x2)) #3#))
|
||||
((< w 1d0) (+ (* (* x1 (sqrt (/ (* -2d0 (log w)) w))) sd) mean))))
|
||||
|
||||
(defun sleep* (time) (sleep (max time (/ (expt 10 7)))))
|
||||
|
||||
(defun dining-philosophers (&key (philosopher-names *philosophers*)
|
||||
(meals 30)
|
||||
(dining-time'(1 2))
|
||||
(thinking-time '(1 2))
|
||||
((stream e) *error-output*))
|
||||
(let* ((count (length philosopher-names))
|
||||
(forks (loop repeat count collect (make-instance 'fork)))
|
||||
(philosophers (loop for i from 0
|
||||
for name in philosopher-names collect
|
||||
(make-instance 'philosopher
|
||||
:left-fork (nth (mod i count) forks)
|
||||
:right-fork (nth (mod (1+ i) count) forks)
|
||||
:name name
|
||||
:meals-left meals)))
|
||||
(condition (bt:make-condition-variable))
|
||||
(lock (bt:make-lock "main loop"))
|
||||
(output-lock (bt:make-lock "output lock")))
|
||||
(dolist (p philosophers)
|
||||
(labels ((think ()
|
||||
(/me "is now thinking")
|
||||
(sleep* (apply #'random-normal thinking-time))
|
||||
(/me "is now hungry")
|
||||
(dine))
|
||||
(dine ()
|
||||
(bt:with-lock-held ((lock-of (left-fork-of p)))
|
||||
(or (bt:acquire-lock (lock-of (right-fork-of p)) nil)
|
||||
(progn (/me "couldn't get a fork and ~
|
||||
returns to thinking")
|
||||
(bt:release-lock (lock-of (left-fork-of p)))
|
||||
(return-from dine (think))))
|
||||
(/me "is eating")
|
||||
(sleep* (apply #'random-normal dining-time))
|
||||
(bt:release-lock (lock-of (right-fork-of p)))
|
||||
(/me "is done eating (~A meals left)"
|
||||
(decf (meals-left-of p))))
|
||||
(cond ((<= (meals-left-of p) 0)
|
||||
(/me "leaves the dining room")
|
||||
(bt:with-lock-held (lock)
|
||||
(setq philosophers (delete p philosophers))
|
||||
(bt:condition-notify condition)))
|
||||
(t (think))))
|
||||
(/me (control &rest args)
|
||||
(bt:with-lock-held (output-lock)
|
||||
(write-sequence (string (name-of p)) e)
|
||||
(write-char #\Space e)
|
||||
(apply #'format e (concatenate 'string control "~%")
|
||||
args))))
|
||||
(bt:make-thread #'think)))
|
||||
(loop (bt:with-lock-held (lock)
|
||||
(when (endp philosophers)
|
||||
(format e "all philosophers are done dining~%")
|
||||
(return)))
|
||||
(bt:with-lock-held (lock)
|
||||
(bt:condition-wait condition lock)))))
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
(ql:quickload '(:stmx :bordeaux-threads))
|
||||
|
||||
(defpackage :dining-philosophers
|
||||
(:use :cl))
|
||||
|
||||
(in-package :dining-philosophers)
|
||||
|
||||
(defstruct philosopher
|
||||
name
|
||||
left-fork
|
||||
right-fork)
|
||||
|
||||
(defparameter *philosophers* '("Aristotle" "Kant" "Spinoza" "Marx" "Russell"))
|
||||
(defparameter *eating-max* 5.0)
|
||||
(defparameter *thinking-max* 5.0)
|
||||
(defvar *log-lock* (bt:make-lock))
|
||||
(defvar *running* nil)
|
||||
|
||||
(defun print-log (name status)
|
||||
(bt:with-lock-held (*log-lock*)
|
||||
(format t "~a is ~a~%" name status)))
|
||||
|
||||
(defun philosopher-cycle (philosopher)
|
||||
"Continously atomically grab and return the left and right forks of the given PHILOSOPHER."
|
||||
(with-slots (name left-fork right-fork) philosopher
|
||||
(loop while *running*
|
||||
do
|
||||
(print-log name "hungry")
|
||||
(stmx:atomic
|
||||
(stmx.util:take left-fork)
|
||||
(stmx.util:take right-fork))
|
||||
(print-log name "eating")
|
||||
(sleep (random *eating-max*))
|
||||
(stmx:atomic
|
||||
(stmx.util:put left-fork t)
|
||||
(stmx.util:put right-fork t))
|
||||
(print-log name "thinking")
|
||||
(sleep (random *thinking-max*)))))
|
||||
|
||||
(defun scenario ()
|
||||
(let ((forks (loop repeat (length *philosophers*) collect (stmx.util:tcell t))))
|
||||
(setf *running* t)
|
||||
(loop for name in *philosophers*
|
||||
for left-fork in forks
|
||||
for right-fork in (append (cdr forks) (list (car forks)))
|
||||
do (let ((philosopher (make-philosopher :name name :left-fork left-fork :right-fork right-fork)))
|
||||
(bt:make-thread (lambda () (philosopher-cycle philosopher))
|
||||
:initial-bindings (cons (cons '*standard-output* *standard-output*)
|
||||
bt:*default-special-bindings*))))))
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
DINING-PHILOSOPHERS> (scenario)
|
||||
Aristotle is hungry
|
||||
Aristotle is eating
|
||||
Kant is hungry
|
||||
Spinoza is hungry
|
||||
Spinoza is eating
|
||||
Marx is hungry
|
||||
NIL
|
||||
Russell is hungry
|
||||
Aristotle is thinking
|
||||
Russell is eating
|
||||
Spinoza is thinking
|
||||
Kant is eating
|
||||
Spinoza is hungry
|
||||
Russell is thinking
|
||||
Marx is eating
|
||||
Kant is thinking
|
||||
Aristotle is hungry
|
||||
Aristotle is eating
|
||||
Marx is thinking
|
||||
Spinoza is eating
|
||||
Spinoza is thinking
|
||||
Marx is hungry
|
||||
Marx is eating
|
||||
Russell is hungry
|
||||
Marx is thinking
|
||||
Kant is hungry
|
||||
Aristotle is thinking
|
||||
Russell is eating
|
||||
Kant is eating
|
||||
Marx is hungry
|
||||
Spinoza is hungry
|
||||
Kant is thinking
|
||||
Spinoza is eating
|
||||
Kant is hungry
|
||||
Aristotle is hungry
|
||||
Russell is thinking
|
||||
Aristotle is eating
|
||||
Aristotle is thinking
|
||||
Aristotle is hungry
|
||||
Aristotle is eating
|
||||
Spinoza is thinking
|
||||
Marx is eating
|
||||
...
|
||||
39
Task/Dining-philosophers/D/dining-philosophers.d
Normal file
39
Task/Dining-philosophers/D/dining-philosophers.d
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import std.stdio, std.algorithm, std.string, std.parallelism,
|
||||
core.sync.mutex;
|
||||
|
||||
void eat(in size_t i, in string name, Mutex[] forks) {
|
||||
writeln(name, " is hungry.");
|
||||
immutable j = (i + 1) % forks.length;
|
||||
|
||||
// Take forks i and j. The lower one first to prevent deadlock.
|
||||
auto fork1 = forks[min(i, j)];
|
||||
auto fork2 = forks[max(i, j)];
|
||||
|
||||
fork1.lock;
|
||||
scope(exit) fork1.unlock;
|
||||
|
||||
fork2.lock;
|
||||
scope(exit) fork2.unlock;
|
||||
|
||||
writeln(name, " is eating.");
|
||||
writeln(name, " is full.");
|
||||
}
|
||||
|
||||
void think(in string name) {
|
||||
writeln(name, " is thinking.");
|
||||
}
|
||||
|
||||
void main() {
|
||||
const philosophers = "Aristotle Kant Spinoza Marx Russell".split;
|
||||
Mutex[philosophers.length] forks;
|
||||
foreach (ref fork; forks)
|
||||
fork = new Mutex;
|
||||
|
||||
defaultPoolThreads = forks.length;
|
||||
foreach (i, philo; taskPool.parallel(philosophers)) {
|
||||
foreach (immutable _; 0 .. 100) {
|
||||
eat(i, philo, forks);
|
||||
philo.think;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Task/Dining-philosophers/Delphi/dining-philosophers.delphi
Normal file
102
Task/Dining-philosophers/Delphi/dining-philosophers.delphi
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
program dining_philosophers;
|
||||
uses
|
||||
Classes,
|
||||
SysUtils,
|
||||
SyncObjs;
|
||||
|
||||
const
|
||||
PHIL_COUNT = 5;
|
||||
LIFESPAN = 7;
|
||||
DELAY_RANGE = 950;
|
||||
DELAY_LOW = 50;
|
||||
PHIL_NAMES: array[1..PHIL_COUNT] of string = ('Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell');
|
||||
type
|
||||
TFork = TCriticalSection;
|
||||
// TPhilosopher = class;
|
||||
TPhilosopher = class(TThread)
|
||||
private
|
||||
FName: string;
|
||||
FFirstFork, FSecondFork: TFork;
|
||||
protected
|
||||
procedure Execute; override;
|
||||
public
|
||||
constructor Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
end;
|
||||
|
||||
var
|
||||
Forks: array[1..PHIL_COUNT] of TFork;
|
||||
Philosophers: array[1..PHIL_COUNT] of TPhilosopher;
|
||||
|
||||
procedure TPhilosopher.Execute;
|
||||
var
|
||||
LfSpan: Integer;
|
||||
begin
|
||||
LfSpan := LIFESPAN;
|
||||
while LfSpan > 0 do
|
||||
begin
|
||||
Dec(LfSpan);
|
||||
WriteLn(FName, ' sits down at the table');
|
||||
FFirstFork.Acquire;
|
||||
FSecondFork.Acquire;
|
||||
WriteLn(FName, ' eating');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
FSecondFork.Release;
|
||||
FFirstFork.Release;
|
||||
WriteLn(FName, ' is full and leaves the table');
|
||||
if LfSpan = 0 then
|
||||
continue;
|
||||
WriteLn(FName, ' thinking');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
WriteLn(FName, ' is hungry');
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TPhilosopher.Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
begin
|
||||
inherited Create(True);
|
||||
FName := aName;
|
||||
if aForkIdx1 < aForkIdx2 then
|
||||
begin
|
||||
FFirstFork := Forks[aForkIdx1];
|
||||
FSecondFork := Forks[aForkIdx2];
|
||||
end
|
||||
else
|
||||
begin
|
||||
FFirstFork := Forks[aForkIdx2];
|
||||
FSecondFork := Forks[aForkIdx1];
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure DinnerBegin;
|
||||
var
|
||||
I: Integer;
|
||||
Phil: TPhilosopher;
|
||||
begin
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Forks[I] := TFork.Create;
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Philosophers[I] := TPhilosopher.Create(PHIL_NAMES[I], I, Succ(I mod PHIL_COUNT));
|
||||
for Phil in Philosophers do
|
||||
Phil.Start;
|
||||
end;
|
||||
|
||||
procedure WaitForDinnerOver;
|
||||
var
|
||||
Phil: TPhilosopher;
|
||||
Fork: TFork;
|
||||
begin
|
||||
for Phil in Philosophers do
|
||||
begin
|
||||
Phil.WaitFor;
|
||||
Phil.Free;
|
||||
end;
|
||||
for Fork in Forks do
|
||||
Fork.Free;
|
||||
end;
|
||||
|
||||
begin
|
||||
Randomize;
|
||||
DinnerBegin;
|
||||
WaitForDinnerOver;
|
||||
readln;
|
||||
end.
|
||||
39
Task/Dining-philosophers/EchoLisp/dining-philosophers-1.l
Normal file
39
Task/Dining-philosophers/EchoLisp/dining-philosophers-1.l
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
(lib 'tasks)
|
||||
|
||||
(define names #(Aristotle Kant Spinoza Marx Russell))
|
||||
(define abouts #("Wittgenstein" "the nature of the World" "Kant" "starving"
|
||||
"spaghettis" "the essence of things" "Ω" "📞" "⚽️" "🍅" "🌿"
|
||||
"philosophy" "💔" "👠" "rosetta code" "his to-do list" ))
|
||||
(define (about) (format "thinking about %a." (vector-ref abouts (random (vector-length abouts)))))
|
||||
|
||||
;; statistics
|
||||
(define rounds (make-vector 5 0))
|
||||
(define (eat i) (vector-set! rounds i (1+ (vector-ref rounds i))))
|
||||
|
||||
;; forks are resources = semaphores
|
||||
(define (left i) i)
|
||||
(define (right i) (modulo (1+ i) 5))
|
||||
(define forks (for/vector ((i 5)) (make-semaphore 1)))
|
||||
(define (fork i) (vector-ref forks i))
|
||||
|
||||
(define laquais (make-semaphore 4))
|
||||
|
||||
;; philosophers tasks
|
||||
(define (philo i)
|
||||
;; thinking
|
||||
(writeln (vector-ref names i) (about))
|
||||
(sleep (+ 2000 (random 1000)))
|
||||
(wait laquais)
|
||||
;; get forks
|
||||
(writeln (vector-ref names i) 'sitting)
|
||||
(wait (fork (left i)))
|
||||
(wait (fork (right i)))
|
||||
(writeln (vector-ref names i) 'eating)
|
||||
(eat i)
|
||||
(sleep (+ 6000 (random 1000)))
|
||||
;; put-forks
|
||||
(signal (fork (left i)))
|
||||
(signal (fork (right i)))
|
||||
(signal laquais)
|
||||
i)
|
||||
(define tasks (for/vector ((i 5)) (make-task philo i)))
|
||||
10
Task/Dining-philosophers/EchoLisp/dining-philosophers-2.l
Normal file
10
Task/Dining-philosophers/EchoLisp/dining-philosophers-2.l
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
(define (observe dummmy)
|
||||
(writeln 'observer 'rounds= rounds)
|
||||
#t)
|
||||
(define observer (make-task observe #t ))
|
||||
|
||||
(define (dinner)
|
||||
(task-run observer 5000)
|
||||
(for ((t tasks)) (task-run t)))
|
||||
|
||||
(dinner)
|
||||
58
Task/Dining-philosophers/Eiffel/dining-philosophers-1.e
Normal file
58
Task/Dining-philosophers/Eiffel/dining-philosophers-1.e
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
class
|
||||
DINING_PHILOSOPHERS
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make
|
||||
-- Create philosophers and forks.
|
||||
local
|
||||
first_fork: separate FORK
|
||||
left_fork: separate FORK
|
||||
right_fork: separate FORK
|
||||
philosopher: separate PHILOSOPHER
|
||||
i: INTEGER
|
||||
do
|
||||
print ("Dining Philosophers%N" + philosopher_count.out + " philosophers, " + round_count.out + " rounds%N%N")
|
||||
create philosophers.make
|
||||
from
|
||||
i := 1
|
||||
create first_fork.make (philosopher_count, 1)
|
||||
left_fork := first_fork
|
||||
until
|
||||
i > philosopher_count
|
||||
loop
|
||||
if i < philosopher_count then
|
||||
create right_fork.make (i, i + 1)
|
||||
else
|
||||
right_fork := first_fork
|
||||
end
|
||||
create philosopher.make (i, left_fork, right_fork, round_count)
|
||||
philosophers.extend (philosopher)
|
||||
left_fork := right_fork
|
||||
i := i + 1
|
||||
end
|
||||
philosophers.do_all (agent launch_philosopher)
|
||||
print ("Make Done!%N")
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
philosopher_count: INTEGER = 5
|
||||
-- Number of philosophers.
|
||||
|
||||
round_count: INTEGER = 30
|
||||
-- Number of times each philosopher should eat.
|
||||
|
||||
philosophers: LINKED_LIST [separate PHILOSOPHER]
|
||||
-- List of philosophers.
|
||||
|
||||
launch_philosopher (a_philosopher: separate PHILOSOPHER)
|
||||
-- Launch a_philosopher.
|
||||
do
|
||||
a_philosopher.live
|
||||
end
|
||||
|
||||
end -- class DINING_PHILOSOPHERS
|
||||
110
Task/Dining-philosophers/Eiffel/dining-philosophers-2.e
Normal file
110
Task/Dining-philosophers/Eiffel/dining-philosophers-2.e
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
class
|
||||
PHILOSOPHER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (philosopher: INTEGER; left, right: separate FORK; rounds: INTEGER)
|
||||
-- Initialize with ID of `philosopher', forks `left' and `right', and for `rounds' times to eat.
|
||||
require
|
||||
valid_id: philosopher >= 1
|
||||
valid_times_to_eat: rounds >= 1
|
||||
do
|
||||
id := philosopher
|
||||
left_fork := left
|
||||
right_fork := right
|
||||
round_count := rounds
|
||||
report ("announced")
|
||||
ensure
|
||||
id_set: id = philosopher
|
||||
left_fork_set: left_fork = left
|
||||
right_fork_set: right_fork = right
|
||||
rounds_set: round_count = rounds
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
id: INTEGER
|
||||
-- Philosopher's id.
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
live
|
||||
-- Model philosopher's life.
|
||||
do
|
||||
from
|
||||
report ("joined")
|
||||
has_eaten_count := 0
|
||||
until
|
||||
has_eaten_count >= round_count
|
||||
loop
|
||||
think
|
||||
eat (left_fork, right_fork)
|
||||
end
|
||||
report ("done")
|
||||
end
|
||||
|
||||
eat (left, right: separate FORK)
|
||||
-- Eat, having acquired `left' and `right' forks.
|
||||
do
|
||||
-- Take forks.
|
||||
report ("taking forks")
|
||||
left.pick (Current)
|
||||
right.pick (Current)
|
||||
-- Eat.
|
||||
report ("eating")
|
||||
delay (200)
|
||||
-- Put forks back.
|
||||
report ("putting forks back")
|
||||
left.put (Current)
|
||||
right.put (Current)
|
||||
-- Report statistics.
|
||||
has_eaten_count := has_eaten_count + 1
|
||||
report ("has eaten " + has_eaten_count.out + " times")
|
||||
end
|
||||
|
||||
think
|
||||
-- Think ... for a short time.
|
||||
do
|
||||
report ("thinking")
|
||||
delay (400)
|
||||
end
|
||||
|
||||
feature {NONE} -- Output
|
||||
|
||||
report (task: STRING)
|
||||
-- Report about execution of the specified `task'.
|
||||
do
|
||||
print ("Philosopher " + id.out + ": " + task + ".%N")
|
||||
end
|
||||
|
||||
feature {NONE} -- Timing
|
||||
|
||||
delay (milliseconds: INTEGER_64)
|
||||
-- Delay execution by `milliseconds'.
|
||||
do
|
||||
(create {EXECUTION_ENVIRONMENT}).sleep (milliseconds * 1_000_000)
|
||||
end
|
||||
|
||||
feature {NONE} -- Status
|
||||
|
||||
round_count: INTEGER
|
||||
-- Number of times philosopher should eat.
|
||||
|
||||
has_eaten_count: INTEGER
|
||||
-- Number of times philosopher has eaten so far.
|
||||
|
||||
left_fork: separate FORK
|
||||
-- Left fork used for eating.
|
||||
|
||||
right_fork: separate FORK
|
||||
-- Right fork used for eating.
|
||||
|
||||
invariant
|
||||
valid_id: id >= 1
|
||||
valid_round_count: round_count >= 1
|
||||
valid_has_eaten_count: has_eaten_count <= round_count
|
||||
|
||||
end -- class PHILOSOPHER
|
||||
34
Task/Dining-philosophers/Eiffel/dining-philosophers-3.e
Normal file
34
Task/Dining-philosophers/Eiffel/dining-philosophers-3.e
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
class
|
||||
FORK
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (left, right: INTEGER)
|
||||
-- Initialize between philosophers `left' and `right'.
|
||||
do
|
||||
id := left.out + "F" + right.out
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
id: STRING
|
||||
-- Identification: `F' enclosed by adjacent philosopher id's.
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
pick (philosopher: separate PHILOSOPHER)
|
||||
-- Report fork picked up.
|
||||
do
|
||||
print ("Fork " + id + " picked up by Philosopher " + philosopher.id.out + ".%N")
|
||||
end
|
||||
|
||||
put (philosopher: separate PHILOSOPHER)
|
||||
-- Report fork put back.
|
||||
do
|
||||
print ("Fork " + id + " put back by Philosopher " + philosopher.id.out + ".%N")
|
||||
end
|
||||
|
||||
end -- class FORK
|
||||
121
Task/Dining-philosophers/Elixir/dining-philosophers.elixir
Normal file
121
Task/Dining-philosophers/Elixir/dining-philosophers.elixir
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
defmodule Philosopher do
|
||||
|
||||
defstruct missing: [], clean: [], promised: []
|
||||
|
||||
def run_demo do
|
||||
pid1 = spawn(__MODULE__, :init, ["Russell"])
|
||||
pid2 = spawn(__MODULE__, :init, ["Marx"])
|
||||
pid3 = spawn(__MODULE__, :init, ["Spinoza"])
|
||||
pid4 = spawn(__MODULE__, :init, ["Kant"])
|
||||
pid5 = spawn(__MODULE__, :init, ["Aristotle"])
|
||||
|
||||
# a chopstick is simply represented by the pid of the neighbour that shares it.
|
||||
|
||||
send(pid1, {:run, %Philosopher{}})
|
||||
send(pid2, {:run, %Philosopher{missing: [pid1]}})
|
||||
send(pid3, {:run, %Philosopher{missing: [pid2]}})
|
||||
send(pid4, {:run, %Philosopher{missing: [pid3]}})
|
||||
send(pid5, {:run, %Philosopher{missing: [pid1, pid4]}})
|
||||
end
|
||||
|
||||
def init(philosopher_name) do
|
||||
receive do
|
||||
{:run, state} ->
|
||||
spawn(__MODULE__, :change_state, [self()])
|
||||
case flip_coin() do
|
||||
:heads -> thinking(philosopher_name, state)
|
||||
:tails -> hungry(philosopher_name, state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp thinking(philosopher_name, state) do
|
||||
receive do
|
||||
{:change_state} ->
|
||||
hungry(philosopher_name, state)
|
||||
{:chopstick_request, pid} ->
|
||||
if clean?(pid, state) do
|
||||
thinking(philosopher_name, promise_chopstick(philosopher_name, pid, state))
|
||||
else
|
||||
give_chopstick(philosopher_name, self(), pid)
|
||||
%{missing: missing} = state
|
||||
thinking(philosopher_name, %{state | missing: [pid | missing]})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp hungry(philosopher_name, state) do
|
||||
IO.puts "#{philosopher_name} is hungry."
|
||||
%{missing: missing} = state
|
||||
for pid <- missing, do: request_chopstick(philosopher_name, self(), pid)
|
||||
wait_for_chopsticks(philosopher_name, state)
|
||||
end
|
||||
|
||||
defp wait_for_chopsticks(philosopher_name, state) do
|
||||
if has_chopsticks?(state) do
|
||||
eating(philosopher_name, state)
|
||||
end
|
||||
receive do
|
||||
{:chopstick_request, pid} ->
|
||||
if clean?(pid, state) do
|
||||
wait_for_chopsticks(philosopher_name, promise_chopstick(philosopher_name, pid, state))
|
||||
else
|
||||
give_chopstick(philosopher_name, self(), pid)
|
||||
request_chopstick(philosopher_name, self(), pid)
|
||||
%{missing: missing} = state
|
||||
wait_for_chopsticks(philosopher_name, %{state | missing: [pid | missing]})
|
||||
end
|
||||
{:chopstick_response, pid} ->
|
||||
%{missing: missing, clean: clean} = state
|
||||
wait_for_chopsticks(philosopher_name, %{state | missing: List.delete(missing, pid), clean: [pid | clean]})
|
||||
end
|
||||
end
|
||||
|
||||
defp eating(philosopher_name, state) do
|
||||
IO.puts "*** #{philosopher_name} is eating."
|
||||
receive do
|
||||
{:change_state} ->
|
||||
%{promised: promised} = state
|
||||
for pid <- promised, do: give_chopstick(philosopher_name, self(), pid)
|
||||
thinking(philosopher_name, %Philosopher{missing: promised})
|
||||
end
|
||||
end
|
||||
|
||||
defp clean?(pid, state) do
|
||||
%{clean: clean} = state
|
||||
Enum.member?(clean, pid)
|
||||
end
|
||||
|
||||
defp has_chopsticks?(state) do
|
||||
%{missing: missing} = state
|
||||
Enum.empty?(missing)
|
||||
end
|
||||
|
||||
defp promise_chopstick(philosopher_name, pid, state) do
|
||||
IO.puts "#{philosopher_name} promises a chopstick."
|
||||
%{promised: promised} = state
|
||||
%{state | promised: [pid | promised]}
|
||||
end
|
||||
|
||||
defp request_chopstick(philosopher_name, snd_pid, recv_pid) do
|
||||
IO.puts "#{philosopher_name} requests a chopstick."
|
||||
send(recv_pid, {:chopstick_request, snd_pid})
|
||||
end
|
||||
|
||||
defp give_chopstick(philosopher_name, snd_pid, recv_pid) do
|
||||
IO.puts "#{philosopher_name} gives a chopstick."
|
||||
send(recv_pid, {:chopstick_response, snd_pid})
|
||||
end
|
||||
|
||||
defp flip_coin do
|
||||
case Enum.random(0..1) do
|
||||
0 -> :heads
|
||||
1 -> :tails
|
||||
end
|
||||
end
|
||||
|
||||
def change_state(pid) do
|
||||
Process.sleep(Enum.random(1..10) * 1000)
|
||||
send(pid, {:change_state})
|
||||
change_state(pid)
|
||||
end
|
||||
123
Task/Dining-philosophers/Erlang/dining-philosophers-1.erl
Normal file
123
Task/Dining-philosophers/Erlang/dining-philosophers-1.erl
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
%%%
|
||||
%%% to compile and run:
|
||||
%%% $ erl
|
||||
%%% > c(rosetta).
|
||||
%%% {ok,rosetta}
|
||||
%%% > rosetta:dining().
|
||||
%%%
|
||||
%%% contributor: bksteele
|
||||
%%%
|
||||
-module(rosetta).
|
||||
-export([dining/0]).
|
||||
|
||||
sleep(T) ->
|
||||
receive
|
||||
after T ->
|
||||
true
|
||||
end.
|
||||
|
||||
doForks(ForkList) ->
|
||||
receive
|
||||
{grabforks, {Left, Right}} ->
|
||||
doForks(ForkList -- [Left, Right]);
|
||||
{releaseforks, {Left, Right}} ->
|
||||
doForks([Left, Right| ForkList]);
|
||||
{available, {Left, Right}, Sender} ->
|
||||
Sender ! {areAvailable,
|
||||
lists:member(Left, ForkList)
|
||||
andalso lists:member(Right, ForkList)},
|
||||
doForks(ForkList);
|
||||
{die} -> io:format("Forks put away.~n")
|
||||
end.
|
||||
|
||||
areAvailable(Forks) ->
|
||||
forks ! {available, Forks, self()},
|
||||
receive
|
||||
{areAvailable, false} -> false;
|
||||
{areAvailable, true} -> true
|
||||
end.
|
||||
|
||||
|
||||
processWaitList([]) -> false;
|
||||
processWaitList([H|T]) ->
|
||||
{Client, Forks} = H,
|
||||
case areAvailable(Forks) of
|
||||
true -> Client ! {served},
|
||||
true;
|
||||
false -> processWaitList(T)
|
||||
end.
|
||||
|
||||
doWaiter([], 0, 0, false) ->
|
||||
forks ! {die},
|
||||
io:format("Waiter is leaving.~n"),
|
||||
diningRoom ! {allgone};
|
||||
doWaiter(WaitList, ClientCount, EatingCount, Busy) ->
|
||||
receive
|
||||
{waiting, Client} ->
|
||||
WaitList1 = [Client|WaitList],
|
||||
% add to waiting list
|
||||
case (not Busy) and (EatingCount<2) of
|
||||
true ->
|
||||
Busy1 = processWaitList(WaitList1);
|
||||
false -> Busy1 = Busy
|
||||
end,
|
||||
doWaiter(WaitList1, ClientCount, EatingCount, Busy1);
|
||||
|
||||
{eating, Client} ->
|
||||
doWaiter(WaitList -- [Client], ClientCount, EatingCount+1, false);
|
||||
|
||||
{finished} ->
|
||||
doWaiter(WaitList, ClientCount, EatingCount-1,
|
||||
processWaitList(WaitList));
|
||||
{leaving} ->
|
||||
doWaiter(WaitList, ClientCount-1, EatingCount, Busy)
|
||||
end.
|
||||
|
||||
|
||||
philosopher(Name, _Forks, 0) ->
|
||||
io:format("~s is leaving.~n", [Name]),
|
||||
waiter ! {leaving};
|
||||
philosopher(Name, Forks, Cycle) ->
|
||||
io:format("~s is thinking.~n", [Name]),
|
||||
sleep(rand:uniform(1000)),
|
||||
io:format("~s is hungry.~n", [Name]),
|
||||
% sit at table
|
||||
waiter ! {waiting, {self(), Forks}},
|
||||
|
||||
receive
|
||||
{served} -> forks ! {grabforks, Forks},
|
||||
% grab forks
|
||||
waiter ! {eating, {self(), Forks}},
|
||||
% start eating
|
||||
io:format("~s is eating.~n", [Name])
|
||||
end,
|
||||
|
||||
sleep(rand:uniform(1000)),
|
||||
% put forks down
|
||||
forks ! {releaseforks, Forks},
|
||||
waiter ! {finished},
|
||||
|
||||
philosopher(Name, Forks, Cycle-1).
|
||||
|
||||
|
||||
dining() -> AllForks = [1, 2, 3, 4, 5],
|
||||
Clients = 5,
|
||||
register(diningRoom, self()),
|
||||
|
||||
register(forks,
|
||||
spawn(fun() -> doForks(AllForks) end)),
|
||||
register(waiter,
|
||||
spawn(fun() -> doWaiter([], Clients, 0, false) end)),
|
||||
% run for 7 cycles
|
||||
Life_span = 7,
|
||||
spawn(fun() -> philosopher('Aristotle', {5, 1}, Life_span) end),
|
||||
spawn(fun() -> philosopher('Kant', {1, 2}, Life_span) end),
|
||||
spawn(fun() -> philosopher('Spinoza', {2, 3}, Life_span) end),
|
||||
spawn(fun() -> philosopher('Marx', {3, 4}, Life_span) end),
|
||||
spawn(fun() -> philosopher('Russell', {4, 5}, Life_span) end),
|
||||
|
||||
receive
|
||||
{allgone} -> io:format("Dining room closed.~n")
|
||||
|
||||
end,
|
||||
unregister(diningRoom).
|
||||
197
Task/Dining-philosophers/Erlang/dining-philosophers-2.erl
Normal file
197
Task/Dining-philosophers/Erlang/dining-philosophers-2.erl
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
%%% This version uses free-running 'phil' agents (actors) and
|
||||
%%% state machines representing the forks.
|
||||
%%%
|
||||
%%% Usage to compile and run:
|
||||
%%% $ erl
|
||||
%%% > c(dining).
|
||||
%%% {ok,dining}
|
||||
%%% > dining:start().
|
||||
%%%
|
||||
|
||||
-module( dining).
|
||||
-export(
|
||||
[ start/0
|
||||
]).
|
||||
-vsn( 1).
|
||||
-date( '6/2020').
|
||||
-author( bksteele).
|
||||
-email( 'drbenkman@gmail.com').
|
||||
|
||||
%% fork messages: grab | drop | quit
|
||||
%% a quit message is accepted only when State = available
|
||||
%% @param Id numeric identification of object
|
||||
%% @param State: available | in_use
|
||||
|
||||
fork( Id, available ) ->
|
||||
receive
|
||||
{ From, Who, grab} ->
|
||||
From ! { self(), Who, Id}
|
||||
, fork( Id, in_use)
|
||||
;
|
||||
{ From, quit} ->
|
||||
From ! { quit}
|
||||
, ok
|
||||
end
|
||||
;
|
||||
fork( Id, in_use ) ->
|
||||
receive
|
||||
{ From, Who, drop} ->
|
||||
From ! { self(), Who, Id}
|
||||
, fork( Id, available)
|
||||
end
|
||||
.
|
||||
|
||||
%% sleep/1 : Integer -> ok
|
||||
%% sleep pauses a process for T milliseconds.
|
||||
%% @param T milliseconds for the time period
|
||||
|
||||
sleep(T) ->
|
||||
receive
|
||||
after T -> true
|
||||
end
|
||||
.
|
||||
|
||||
%% grab/2 : Pid String -> ()
|
||||
%% Fork is the shared resource (a process object).
|
||||
%% Who is the name of the acting process.
|
||||
%% grab encapsulates message transmission.
|
||||
%% @param Fork pid to which to send messages
|
||||
%% @param Who name of the sender
|
||||
|
||||
grab( Fork, Who) ->
|
||||
Fork ! { self(), Who, grab}
|
||||
, receive
|
||||
{ Fork, Who, _Id} -> ok
|
||||
end
|
||||
.
|
||||
|
||||
%% drop/2 : Pid String -> ()
|
||||
%% Fork is the shared resource (a process object).
|
||||
%% Who is the name of the acting process.
|
||||
%% drop encapsulates message transmission.
|
||||
%%
|
||||
%% @param Fork pid to which to send messages
|
||||
%% @param Who name of the sender
|
||||
|
||||
drop( Fork, Who) ->
|
||||
Fork ! { self(), Who, drop}
|
||||
, receive
|
||||
{ Fork, Who, _Id} -> ok
|
||||
end
|
||||
.
|
||||
|
||||
|
||||
%% phil/3 : String List{Id,Pid} Integer -> ok
|
||||
%% phil/3 philosopher process uses a fork process.
|
||||
%% phil uses two fork objects for n eating cycles.
|
||||
%% A phil needs the pids of resource to communicate,
|
||||
%% and the names of the fork resources it uses.
|
||||
%% @param Name the string name of the philosopher
|
||||
%% @param List{Id, Pid} 2 pairs of Id and Fork
|
||||
%% @param Cycle the number of cycles to run
|
||||
|
||||
phil( Name, [{LId, Left}, {RId, Right}], Cycle)
|
||||
when LId > RId ->
|
||||
% swap so that process picks numerically lower first.
|
||||
% the swap introduces asymmetry to prevent deadlock.
|
||||
phil( Name, {RId, Right}, {LId, Left}, Cycle)
|
||||
;
|
||||
phil( Name, [{LId, Left}, {RId, Right}], Cycle) ->
|
||||
phil( Name, {LId, Left}, {RId, Right}, Cycle).
|
||||
|
||||
|
||||
%% phil/4 : String {LId,LeftF} {RId,RightF} Integer -> ok
|
||||
%% phil/4 philosopher process uses a fork process.
|
||||
%% phil uses two fork objects for n eating cycles.
|
||||
%% A phil needs pids of resource to communicate
|
||||
%% and the names of the fork resources it uses.
|
||||
%% @param Name the string name of the philosopher
|
||||
%% @param {LeftId, Fork} pair of Id and Fork pid
|
||||
%% @param {RightId, Fork} pair of Id and Fork pid
|
||||
%% @param Cycle the number of cycles to run
|
||||
|
||||
phil( Name, _LFork, _RFork, 0) ->
|
||||
io:format( "~s is done.~n", [Name])
|
||||
;
|
||||
phil( Name, {LId, Left}, {RId, Right}, Cycle) ->
|
||||
|
||||
io:format( "~s is thinking.~n", [Name])
|
||||
, sleep( rand:uniform( 1000))
|
||||
, io:format( "~s is hungry.~n", [Name])
|
||||
|
||||
, grab( Left, Name)
|
||||
, grab( Right, Name)
|
||||
|
||||
, io:format( "~s is eating.~n", [Name])
|
||||
, sleep( rand:uniform( 1000))
|
||||
|
||||
, drop( Left, Name)
|
||||
, drop( Right, Name)
|
||||
|
||||
, phil( Name, [{LId, Left}, {RId, Right}]
|
||||
, Cycle - 1)
|
||||
.
|
||||
|
||||
%% make_forks/1 : N -> List{Id, Fork}
|
||||
|
||||
make_forks( N) when N > 0 -> make_forks( N, []).
|
||||
|
||||
%% make_forks/2 : N List{Id, Fork}
|
||||
|
||||
make_forks( 0, Forks ) -> lists:reverse( Forks)
|
||||
;
|
||||
make_forks( N, Forks) ->
|
||||
% create and run the fork processes
|
||||
Pair = { N, spawn(
|
||||
fun() -> fork( N, available) end) }
|
||||
, make_forks( N-1
|
||||
, lists:append( Forks, [Pair] ))
|
||||
.
|
||||
|
||||
%% make_phils/2 : Names, ForkList -> List{String}
|
||||
|
||||
make_phils( Names, Forks)
|
||||
when length( Names) > 0 ->
|
||||
make_phils( Names, Forks, [])
|
||||
.
|
||||
|
||||
%% make_phils/3 : Names Forks PL -> List{Fun}
|
||||
%% make_phil/3 hard-codes the eat cycle count to 7
|
||||
|
||||
make_phils( [], _Forks, PhilList) -> PhilList
|
||||
;
|
||||
make_phils( [Hn|Tn], [Lf, Rf |FList], PhilList) ->
|
||||
% create a phil process function but do not run yet
|
||||
Phil = fun() -> phil( Hn, [Lf, Rf], 7) end
|
||||
, make_phils( Tn, rot( [Lf, Rf |FList], 1)
|
||||
, lists:append( PhilList, [Phil]))
|
||||
.
|
||||
|
||||
%% rot/2 : List Num -> List
|
||||
%% rotate or roll a list by N slots, and return new list
|
||||
|
||||
rot( List, 0 ) -> List
|
||||
;
|
||||
rot( [H], 1 ) -> [H]
|
||||
;
|
||||
rot( [H|List], N ) ->
|
||||
rot( lists:append( List, [H]), N - 1)
|
||||
.
|
||||
|
||||
%% start free-running philosopher agents competing for Forks
|
||||
%% start is fixed with N = 5 philosophers and 5 forks.
|
||||
|
||||
start() ->
|
||||
% create Fork list
|
||||
N = 5
|
||||
, Forks = make_forks( N)
|
||||
|
||||
, Names = [ "Aristotle", "Kant"
|
||||
, "Spinoza", "Marx", "Russell"]
|
||||
|
||||
, Phils = make_phils( Names, Forks)
|
||||
|
||||
% run the philosophers now
|
||||
, [spawn( P) || P <- Phils]
|
||||
, ok
|
||||
.
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
constant FREE = 0, LOCKED = 1
|
||||
sequence forks
|
||||
forks = repeat(FREE,5)
|
||||
|
||||
procedure person(sequence name, integer left_fork, integer right_fork)
|
||||
while 1 do
|
||||
while forks[left_fork] = LOCKED or forks[right_fork] = LOCKED do
|
||||
if forks[left_fork] = FREE then
|
||||
puts(1, name & " hasn't right fork.\n")
|
||||
elsif forks[right_fork] = FREE then
|
||||
puts(1, name & " hasn't left fork.\n")
|
||||
else
|
||||
puts(1, name & " hasn't both forks.\n")
|
||||
end if
|
||||
puts(1, name & " is waiting.\n")
|
||||
task_yield()
|
||||
end while
|
||||
|
||||
puts(1, name & " grabs forks.\n")
|
||||
forks[left_fork] = LOCKED
|
||||
forks[right_fork] = LOCKED
|
||||
for i = 1 to rand(10) do
|
||||
puts(1, name & " is eating.\n")
|
||||
task_yield()
|
||||
end for
|
||||
puts(1, name & " puts forks down and leaves the dinning room.\n")
|
||||
forks[left_fork] = FREE
|
||||
forks[right_fork] = FREE
|
||||
|
||||
for i = 1 to rand(10) do
|
||||
puts(1, name & " is thinking.\n")
|
||||
task_yield()
|
||||
end for
|
||||
puts(1, name & " becomes hungry.\n")
|
||||
end while
|
||||
end procedure
|
||||
|
||||
integer rid
|
||||
atom taskid
|
||||
rid = routine_id("person")
|
||||
taskid = task_create(rid,{"Aristotle",1,2})
|
||||
task_schedule(taskid,{1,2})
|
||||
taskid = task_create(rid,{"Kant",2,3})
|
||||
task_schedule(taskid,{1,2})
|
||||
taskid = task_create(rid,{"Spinoza",3,4})
|
||||
task_schedule(taskid,{1,2})
|
||||
taskid = task_create(rid,{"Marx",4,5})
|
||||
task_schedule(taskid,{1,2})
|
||||
taskid = task_create(rid,{"Russell",5,1})
|
||||
task_schedule(taskid,{1,2})
|
||||
|
||||
while get_key() = -1 do
|
||||
task_yield()
|
||||
end while
|
||||
52
Task/Dining-philosophers/F-Sharp/dining-philosophers.fs
Normal file
52
Task/Dining-philosophers/F-Sharp/dining-philosophers.fs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
open System
|
||||
|
||||
let flip f x y = f y x
|
||||
|
||||
let rec cycle s = seq { yield! s; yield! cycle s }
|
||||
|
||||
type Agent<'T> = MailboxProcessor<'T>
|
||||
|
||||
type Message = Waiting of (Set<int> * AsyncReplyChannel<unit>) | Done of Set<int>
|
||||
|
||||
let reply (c: AsyncReplyChannel<_>) = c.Reply()
|
||||
|
||||
let strategy forks waiting =
|
||||
let aux, waiting = List.partition (fst >> flip Set.isSubset forks) waiting
|
||||
let forks = aux |> List.map fst |> List.fold (-) forks
|
||||
List.iter (snd >> reply) aux
|
||||
forks, waiting
|
||||
|
||||
let waiter strategy forkCount =
|
||||
Agent<_>.Start(fun inbox ->
|
||||
let rec loop forks waiting =
|
||||
async { let forks, waiting = strategy forks waiting
|
||||
let! msg = inbox.Receive()
|
||||
match msg with
|
||||
| Waiting r -> return! loop forks (waiting @ [r])
|
||||
| Done f -> return! loop (forks + f) waiting }
|
||||
loop (Set.ofList (List.init forkCount id)) [])
|
||||
|
||||
let philosopher (waiter: Agent<_>) name forks =
|
||||
let rng = new Random()
|
||||
let forks = Set.ofArray forks
|
||||
Agent<_>.Start(fun inbox ->
|
||||
let rec loop () =
|
||||
async { printfn "%s is thinking" name
|
||||
do! Async.Sleep(rng.Next(100, 500))
|
||||
printfn "%s is hungry" name
|
||||
do! waiter.PostAndAsyncReply(fun c -> Waiting (forks, c))
|
||||
printfn "%s is eating" name
|
||||
do! Async.Sleep(rng.Next(100, 500))
|
||||
printfn "%s is done eating" name
|
||||
waiter.Post(Done (forks))
|
||||
return! loop () }
|
||||
loop ())
|
||||
|
||||
[<EntryPoint>]
|
||||
let main args =
|
||||
let forks = Seq.init 5 id |> cycle |> Seq.windowed 2 |> Seq.take 5 |> Seq.toList
|
||||
let names = ["plato"; "aristotel"; "kant"; "nietzsche"; "russel"]
|
||||
let waiter = waiter strategy 5
|
||||
List.map2 (philosopher waiter) names forks |> ignore
|
||||
Console.ReadLine() |> ignore
|
||||
0
|
||||
84
Task/Dining-philosophers/Go/dining-philosophers-1.go
Normal file
84
Task/Dining-philosophers/Go/dining-philosophers-1.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"hash/fnv"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Number of philosophers is simply the length of this list.
|
||||
// It is not otherwise fixed in the program.
|
||||
var ph = []string{"Aristotle", "Kant", "Spinoza", "Marx", "Russell"}
|
||||
|
||||
const hunger = 3 // number of times each philosopher eats
|
||||
const think = time.Second / 100 // mean think time
|
||||
const eat = time.Second / 100 // mean eat time
|
||||
|
||||
var fmt = log.New(os.Stdout, "", 0) // for thread-safe output
|
||||
|
||||
var done = make(chan bool)
|
||||
|
||||
// This solution uses channels to implement synchronization.
|
||||
// Sent over channels are "forks."
|
||||
type fork byte
|
||||
|
||||
// A fork object in the program models a physical fork in the simulation.
|
||||
// A separate channel represents each fork place. Two philosophers
|
||||
// have access to each fork. The channels are buffered with capacity = 1,
|
||||
// representing a place for a single fork.
|
||||
|
||||
// Goroutine for philosopher actions. An instance is run for each
|
||||
// philosopher. Instances run concurrently.
|
||||
func philosopher(phName string,
|
||||
dominantHand, otherHand chan fork, done chan bool) {
|
||||
fmt.Println(phName, "seated")
|
||||
// each philosopher goroutine has a random number generator,
|
||||
// seeded with a hash of the philosopher's name.
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(phName))
|
||||
rg := rand.New(rand.NewSource(int64(h.Sum64())))
|
||||
// utility function to sleep for a randomized nominal time
|
||||
rSleep := func(t time.Duration) {
|
||||
time.Sleep(t/2 + time.Duration(rg.Int63n(int64(t))))
|
||||
}
|
||||
for h := hunger; h > 0; h-- {
|
||||
fmt.Println(phName, "hungry")
|
||||
<-dominantHand // pick up forks
|
||||
<-otherHand
|
||||
fmt.Println(phName, "eating")
|
||||
rSleep(eat)
|
||||
dominantHand <- 'f' // put down forks
|
||||
otherHand <- 'f'
|
||||
fmt.Println(phName, "thinking")
|
||||
rSleep(think)
|
||||
}
|
||||
fmt.Println(phName, "satisfied")
|
||||
done <- true
|
||||
fmt.Println(phName, "left the table")
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("table empty")
|
||||
// Create fork channels and start philosopher goroutines,
|
||||
// supplying each goroutine with the appropriate channels
|
||||
place0 := make(chan fork, 1)
|
||||
place0 <- 'f' // byte in channel represents a fork on the table.
|
||||
placeLeft := place0
|
||||
for i := 1; i < len(ph); i++ {
|
||||
placeRight := make(chan fork, 1)
|
||||
placeRight <- 'f'
|
||||
go philosopher(ph[i], placeLeft, placeRight, done)
|
||||
placeLeft = placeRight
|
||||
}
|
||||
// Make one philosopher left handed by reversing fork place
|
||||
// supplied to philosopher's dominant hand.
|
||||
// This makes precedence acyclic, preventing deadlock.
|
||||
go philosopher(ph[0], place0, placeLeft, done)
|
||||
// they are all now busy eating
|
||||
for range ph {
|
||||
<-done // wait for philosphers to finish
|
||||
}
|
||||
fmt.Println("table empty")
|
||||
}
|
||||
59
Task/Dining-philosophers/Go/dining-philosophers-2.go
Normal file
59
Task/Dining-philosophers/Go/dining-philosophers-2.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"hash/fnv"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ph = []string{"Aristotle", "Kant", "Spinoza", "Marx", "Russell"}
|
||||
|
||||
const hunger = 3
|
||||
const think = time.Second / 100
|
||||
const eat = time.Second / 100
|
||||
|
||||
var fmt = log.New(os.Stdout, "", 0)
|
||||
|
||||
var dining sync.WaitGroup
|
||||
|
||||
func philosopher(phName string, dominantHand, otherHand *sync.Mutex) {
|
||||
fmt.Println(phName, "seated")
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(phName))
|
||||
rg := rand.New(rand.NewSource(int64(h.Sum64())))
|
||||
rSleep := func(t time.Duration) {
|
||||
time.Sleep(t/2 + time.Duration(rg.Int63n(int64(t))))
|
||||
}
|
||||
for h := hunger; h > 0; h-- {
|
||||
fmt.Println(phName, "hungry")
|
||||
dominantHand.Lock() // pick up forks
|
||||
otherHand.Lock()
|
||||
fmt.Println(phName, "eating")
|
||||
rSleep(eat)
|
||||
dominantHand.Unlock() // put down forks
|
||||
otherHand.Unlock()
|
||||
fmt.Println(phName, "thinking")
|
||||
rSleep(think)
|
||||
}
|
||||
fmt.Println(phName, "satisfied")
|
||||
dining.Done()
|
||||
fmt.Println(phName, "left the table")
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("table empty")
|
||||
dining.Add(5)
|
||||
fork0 := &sync.Mutex{}
|
||||
forkLeft := fork0
|
||||
for i := 1; i < len(ph); i++ {
|
||||
forkRight := &sync.Mutex{}
|
||||
go philosopher(ph[i], forkLeft, forkRight)
|
||||
forkLeft = forkRight
|
||||
}
|
||||
go philosopher(ph[0], fork0, forkLeft)
|
||||
dining.Wait() // wait for philosphers to finish
|
||||
fmt.Println("table empty")
|
||||
}
|
||||
56
Task/Dining-philosophers/Groovy/dining-philosophers.groovy
Normal file
56
Task/Dining-philosophers/Groovy/dining-philosophers.groovy
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import groovy.transform.Canonical
|
||||
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
@Canonical
|
||||
class Fork {
|
||||
String name
|
||||
Lock lock = new ReentrantLock()
|
||||
|
||||
void pickUp(String philosopher) {
|
||||
lock.lock()
|
||||
println " $philosopher picked up $name"
|
||||
}
|
||||
|
||||
void putDown(String philosopher) {
|
||||
lock.unlock()
|
||||
println " $philosopher put down $name"
|
||||
}
|
||||
}
|
||||
|
||||
@Canonical
|
||||
class Philosopher extends Thread {
|
||||
Fork f1
|
||||
Fork f2
|
||||
|
||||
@Override
|
||||
void run() {
|
||||
def random = new Random()
|
||||
(1..20).each { bite ->
|
||||
println "$name is hungry"
|
||||
f1.pickUp name
|
||||
f2.pickUp name
|
||||
println "$name is eating bite $bite"
|
||||
Thread.sleep random.nextInt(300) + 100
|
||||
f2.putDown name
|
||||
f1.putDown name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void diningPhilosophers(names) {
|
||||
def forks = (1..names.size()).collect { new Fork(name: "Fork $it") }
|
||||
def philosophers = []
|
||||
names.eachWithIndex{ n, i ->
|
||||
def (i1, i2) = [i, (i + 1) % 5]
|
||||
if (i2 < i1) (i1, i2) = [i2, i]
|
||||
|
||||
def p = new Philosopher(name: n, f1: forks[i1], f2: forks[i2])
|
||||
p.start()
|
||||
philosophers << p
|
||||
}
|
||||
philosophers.each { it.join() }
|
||||
}
|
||||
|
||||
diningPhilosophers(['Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell'])
|
||||
65
Task/Dining-philosophers/Haskell/dining-philosophers-1.hs
Normal file
65
Task/Dining-philosophers/Haskell/dining-philosophers-1.hs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
module Philosophers where
|
||||
|
||||
import Control.Monad
|
||||
import Control.Concurrent
|
||||
import Control.Concurrent.STM
|
||||
import System.Random
|
||||
|
||||
-- TMVars are transactional references. They can only be used in transactional actions.
|
||||
-- They are either empty or contain one value. Taking an empty reference fails and
|
||||
-- putting a value in a full reference fails. A transactional action only succeeds
|
||||
-- when all the component actions succeed, else it rolls back and retries until it
|
||||
-- succeeds.
|
||||
-- The Int is just for display purposes.
|
||||
type Fork = TMVar Int
|
||||
|
||||
newFork :: Int -> IO Fork
|
||||
newFork i = newTMVarIO i
|
||||
|
||||
-- The basic transactional operations on forks
|
||||
takeFork :: Fork -> STM Int
|
||||
takeFork fork = takeTMVar fork
|
||||
|
||||
releaseFork :: Int -> Fork -> STM ()
|
||||
releaseFork i fork = putTMVar fork i
|
||||
|
||||
type Name = String
|
||||
|
||||
runPhilosopher :: Name -> (Fork, Fork) -> IO ()
|
||||
runPhilosopher name (left, right) = forever $ do
|
||||
putStrLn (name ++ " is hungry.")
|
||||
|
||||
-- Run the transactional action atomically.
|
||||
-- The type system ensures this is the only way to run transactional actions.
|
||||
(leftNum, rightNum) <- atomically $ do
|
||||
leftNum <- takeFork left
|
||||
rightNum <- takeFork right
|
||||
return (leftNum, rightNum)
|
||||
|
||||
putStrLn (name ++ " got forks " ++ show leftNum ++ " and " ++ show rightNum ++ " and is now eating.")
|
||||
delay <- randomRIO (1,10)
|
||||
threadDelay (delay * 1000000) -- 1, 10 seconds. threadDelay uses nanoseconds.
|
||||
putStrLn (name ++ " is done eating. Going back to thinking.")
|
||||
|
||||
atomically $ do
|
||||
releaseFork leftNum left
|
||||
releaseFork rightNum right
|
||||
|
||||
delay <- randomRIO (1, 10)
|
||||
threadDelay (delay * 1000000)
|
||||
|
||||
philosophers :: [String]
|
||||
philosophers = ["Aristotle", "Kant", "Spinoza", "Marx", "Russel"]
|
||||
|
||||
main = do
|
||||
forks <- mapM newFork [1..5]
|
||||
let namedPhilosophers = map runPhilosopher philosophers
|
||||
forkPairs = zip forks (tail . cycle $ forks)
|
||||
philosophersWithForks = zipWith ($) namedPhilosophers forkPairs
|
||||
|
||||
putStrLn "Running the philosophers. Press enter to quit."
|
||||
|
||||
mapM_ forkIO philosophersWithForks
|
||||
|
||||
-- All threads exit when the main thread exits.
|
||||
getLine
|
||||
29
Task/Dining-philosophers/Haskell/dining-philosophers-2.hs
Normal file
29
Task/Dining-philosophers/Haskell/dining-philosophers-2.hs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
global forks, names
|
||||
|
||||
procedure main(A)
|
||||
names := ["Aristotle","Kant","Spinoza","Marks","Russell"]
|
||||
write("^C to terminate")
|
||||
nP := *names
|
||||
forks := [: |mutex([])\nP :]
|
||||
every p := !nP do thread philosopher(p)
|
||||
delay(-1)
|
||||
end
|
||||
|
||||
procedure philosopher(n)
|
||||
f1 := forks[min(n, n%*forks+1)]
|
||||
f2 := forks[max(n, n%*forks+1)]
|
||||
repeat {
|
||||
write(names[n]," thinking")
|
||||
delay(1000*?5)
|
||||
write(names[n]," hungry")
|
||||
repeat {
|
||||
fork1 := lock(f1)
|
||||
if fork2 := trylock(f2) then {
|
||||
write(names[n]," eating")
|
||||
delay(1000*?5)
|
||||
break (unlock(fork2), unlock(fork1)) # full
|
||||
}
|
||||
unlock(fork1) # Free first fork and go back to waiting
|
||||
}
|
||||
}
|
||||
end
|
||||
43
Task/Dining-philosophers/J/dining-philosophers-1.j
Normal file
43
Task/Dining-philosophers/J/dining-philosophers-1.j
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
reqthreads=: {{ 0&T.@''^:(0>.y-1 T.'')0 }}
|
||||
dispatchwith=: (t.'')every
|
||||
newmutex=: (; 10&T.@0)@>
|
||||
lock=: 11&T.@{:
|
||||
unlock=: 13&T.@{:
|
||||
dl=: 6!:3
|
||||
|
||||
dine=: {{
|
||||
'forkA forkB'=. <"1 /:~ n
|
||||
announce=. m {{ echo m,' ',y }}
|
||||
announce 'will use fork ',(":;{.forkA),' first and put it down last'
|
||||
announce 'will use fork ',(":;{.forkB),' second and put it down first'
|
||||
dl 1
|
||||
while. do.
|
||||
announce 'is hungry'
|
||||
lock forkA
|
||||
announce 'picked up fork ',":;{.forkA
|
||||
lock forkB
|
||||
announce 'picked up fork ',":;{.forkB
|
||||
announce 'is eating'
|
||||
dl 2+(?3e3)%1e3
|
||||
announce 'has finished eating'
|
||||
unlock forkB
|
||||
announce 'has put down fork ',":;{.forkB
|
||||
unlock forkA
|
||||
announce 'has put down fork ',":;{.forkA
|
||||
announce 'has left the room'
|
||||
dl 4+(?1e4)%1e3
|
||||
end.
|
||||
y
|
||||
}}
|
||||
|
||||
start=: {{
|
||||
echo 'Hit enter to exit'
|
||||
dl 1
|
||||
reqthreads 5
|
||||
forks=. newmutex i.5
|
||||
for_philosopher.;:' Aristotle Kant Spinoza Marx Russell' do.
|
||||
forks=. 1|.forks
|
||||
(;philosopher) dine (2{.forks) dispatchwith EMPTY
|
||||
end.
|
||||
exit 1!:1]1
|
||||
}}
|
||||
48
Task/Dining-philosophers/J/dining-philosophers-2.j
Normal file
48
Task/Dining-philosophers/J/dining-philosophers-2.j
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
start''
|
||||
Hit enter to exit
|
||||
Aristotle will use fork 1 first and put it down last
|
||||
Kant will use fork 2 first and put it down last
|
||||
Marx will use fork 0 first and put it down last
|
||||
Spinoza will use fork 3 first and put it down last
|
||||
Russell will use fork 0 first and put it down last
|
||||
Aristotle will use fork 2 second and put it down first
|
||||
Kant will use fork 3 second and put it down first
|
||||
Marx will use fork 4 second and put it down first
|
||||
Spinoza will use fork 4 second and put it down first
|
||||
Russell will use fork 1 second and put it down first
|
||||
Spinoza is hungry
|
||||
Marx is hungry
|
||||
Aristotle is hungry
|
||||
Aristotle picked up fork 1
|
||||
Spinoza picked up fork 3
|
||||
Marx picked up fork 0
|
||||
Kant is hungry
|
||||
Aristotle picked up fork 2
|
||||
Spinoza picked up fork 4
|
||||
Aristotle is eating
|
||||
Spinoza is eating
|
||||
Russell is hungry
|
||||
Aristotle has finished eating
|
||||
Spinoza has finished eating
|
||||
Aristotle has put down fork 2
|
||||
Kant picked up fork 2
|
||||
Spinoza has put down fork 4
|
||||
Marx picked up fork 4
|
||||
Aristotle has put down fork 1
|
||||
Spinoza has put down fork 3
|
||||
Kant picked up fork 3
|
||||
Marx is eating
|
||||
Aristotle has left the room
|
||||
Spinoza has left the room
|
||||
Kant is eating
|
||||
Kant has finished eating
|
||||
Marx has finished eating
|
||||
Kant has put down fork 3
|
||||
Marx has put down fork 4
|
||||
Kant has put down fork 2
|
||||
Marx has put down fork 0
|
||||
Russell picked up fork 0
|
||||
Kant has left the room
|
||||
Marx has left the room
|
||||
Russell picked up fork 1
|
||||
Russell is eating
|
||||
27
Task/Dining-philosophers/J/dining-philosophers-3.j
Normal file
27
Task/Dining-philosophers/J/dining-philosophers-3.j
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
". noun define -. CRLF NB. Fixed tacit simulation code...
|
||||
|
||||
simulate=.
|
||||
''"_@:((<@:(1 -~ 1&({::)) 1} ])@:(([ 0 0&$@(1!:2&2)@:(((6j3 ": 9&({::)) , ':
|
||||
'"_) , ' starts waiting and thinking about hunger.' ,~ 8&({::) {:: 0&({::)))@
|
||||
:(<@:(6&({::) , 8&({::)) 6} ])@:((<@:((0 (0 {:: ])`(<@:(1 {:: ]))`(2 {:: ])}
|
||||
])@:(3 8 2&{)) 2} ])@:(<@:2: 3} ]))@:((<@:((0 (0 {:: ])`(<@:(1 {:: ]))`(2 {::
|
||||
])} ])@:(5 8 4&{)) 4} ])@:(<@:_: 5} ]))`(([ 0 0&$@(1!:2&2)@:(((6j3 ": 9&({::
|
||||
)) , ': '"_) , ' starts eating.' ,~ 8&({::) {:: 0&({::)))@:((<@:((0 (0 {:: ])
|
||||
`(<@:(1 {:: ]))`(2 {:: ])} ])@:(3 8 2&{)) 2} ])@:(<@:1: 3} ]))@:((<@:((0 (0 {
|
||||
:: ])`(<@:(1 {:: ]))`(2 {:: ])} ])@:(5 8 4&{)) 4} ])@:(<@:(_2 * ^.@:?@:0:) 5}
|
||||
])))@.(7&({::) > 1 +/@:= 2&({::))`((<@:(}.@:(6&({::))) 6} ])@:(([ 0 0&$@(1!:
|
||||
2&2)@:(((6j3 ": 9&({::)) , ': '"_) , ' starts eating.' ,~ 8&({::) {:: 0&({::)
|
||||
))@:((<@:((0 (0 {:: ])`(<@:(1 {:: ]))`(2 {:: ])} ])@:(3 8 2&{)) 2} ])@:(<@:1:
|
||||
3} ]))@:((<@:((0 (0 {:: ])`(<@:(1 {:: ]))`(2 {:: ])} ])@:(5 8 4&{)) 4} ])@:(
|
||||
<@:(_2 * ^.@:?@:0:) 5} ])))@:(<@:({.@:(6&({::))) 8} ])^:(1 <: #@:(6&({::)))@:
|
||||
([ 0 0&$@(1!:2&2)@:(((6j3 ": 9&({::)) , ': '"_) , ' starts thinking.' ,~ 8&({
|
||||
::) {:: 0&({::)))@:((<@:((0 (0 {:: ])`(<@:(1 {:: ]))`(2 {:: ])} ])@:(3 8 2&{)
|
||||
) 2} ])@:(<@:0: 3} ]))@:((<@:((0 (0 {:: ])`(<@:(1 {:: ]))`(2 {:: ])} ])@:(5 8
|
||||
4&{)) 4} ])@:(<@:(_1 * ^.@:?@:0:) 5} ])))@.('' ($ ,) 8&({::) { 2&({::)))@:(<
|
||||
@:(0 I.@:= 4&({::)) 8} ])@:(<@:((- <./)@:(4&({::))) 4} ])@:(<@:(9&({::) + <./
|
||||
@:(4&({::))) 9} ])^:(0 < 1&({::))^:_)@:(([ 0 0&$@(1!:2&2)@:(((6j3 ": 9&({::))
|
||||
, ': '"_) , 'All of them start thinking.'"_))@:((0 ; <.@:(2 %~ #@:(0&({::)))
|
||||
) 9 7} ])@:((0:"_1 ,&< (_1 * ^.@:?@:0:)&>)@:(0&({::)) 2 4} ])@:((;:@:(0&({::)
|
||||
) ,&< ''"_) 0 6} ]))@:(,&(;:8$','))@:;
|
||||
|
||||
)
|
||||
17
Task/Dining-philosophers/J/dining-philosophers-4.j
Normal file
17
Task/Dining-philosophers/J/dining-philosophers-4.j
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
'Aristotle Kant Spinoza Marx Russell' simulate 11
|
||||
0.000: All of them start thinking.
|
||||
0.097: Spinoza starts eating.
|
||||
0.474: Aristotle starts eating.
|
||||
0.950: Russell starts waiting and thinking about hunger.
|
||||
1.125: Kant starts waiting and thinking about hunger.
|
||||
2.263: Spinoza starts thinking.
|
||||
2.263: Russell starts eating.
|
||||
2.762: Marx starts waiting and thinking about hunger.
|
||||
2.771: Spinoza starts waiting and thinking about hunger.
|
||||
4.769: Russell starts thinking.
|
||||
4.769: Kant starts eating.
|
||||
4.845: Russell starts waiting and thinking about hunger.
|
||||
5.166: Aristotle starts thinking.
|
||||
5.166: Marx starts eating.
|
||||
5.915: Marx starts thinking.
|
||||
5.915: Spinoza starts eating.
|
||||
30
Task/Dining-philosophers/J/dining-philosophers-5.j
Normal file
30
Task/Dining-philosophers/J/dining-philosophers-5.j
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
'Aristotle Kant Spinoza Marx Russell Laozi Nezahualcoyotl Averroes' simulate 22
|
||||
0.000: All of them start thinking.
|
||||
0.077: Nezahualcoyotl starts eating.
|
||||
0.312: Marx starts eating.
|
||||
0.424: Laozi starts eating.
|
||||
0.502: Kant starts eating.
|
||||
0.541: Marx starts thinking.
|
||||
0.545: Marx starts eating.
|
||||
0.660: Laozi starts thinking.
|
||||
0.715: Laozi starts eating.
|
||||
0.766: Aristotle starts waiting and thinking about hunger.
|
||||
0.871: Laozi starts thinking.
|
||||
0.871: Aristotle starts eating.
|
||||
0.893: Averroes starts waiting and thinking about hunger.
|
||||
1.035: Nezahualcoyotl starts thinking.
|
||||
1.035: Averroes starts eating.
|
||||
1.071: Laozi starts waiting and thinking about hunger.
|
||||
1.168: Kant starts thinking.
|
||||
1.168: Laozi starts eating.
|
||||
1.614: Russell starts waiting and thinking about hunger.
|
||||
1.660: Spinoza starts waiting and thinking about hunger.
|
||||
1.813: Aristotle starts thinking.
|
||||
1.813: Russell starts eating.
|
||||
2.022: Marx starts thinking.
|
||||
2.022: Spinoza starts eating.
|
||||
2.164: Russell starts thinking.
|
||||
2.182: Aristotle starts eating.
|
||||
2.339: Marx starts waiting and thinking about hunger.
|
||||
2.446: Aristotle starts thinking.
|
||||
2.446: Marx starts eating.
|
||||
116
Task/Dining-philosophers/J/dining-philosophers-6.j
Normal file
116
Task/Dining-philosophers/J/dining-philosophers-6.j
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
NB. Quick and dirty tacit toolkit...
|
||||
|
||||
o=. @:
|
||||
c=."_
|
||||
|
||||
ver=. (0:`)([:^:)
|
||||
|
||||
d=. (fix=. (;:'f.')ver) (train=.(;:'`:')ver&6) (an=. <@:((,'0') (,&<) ]))
|
||||
ver=. (an f. o fix'ver')ver o an f.
|
||||
z=. ((an'')`($ ,)`) (`:6)
|
||||
d=. (a0=. `'') (a1=. (@[) ((<'&')`) (`:6)) (a2=. (`(<(":0);_)) (`:6))
|
||||
av=. ((an o fix'a0')`) (`(an o fix'a1')) (`(an o fix'a2') ) (`:6)
|
||||
|
||||
Fetch=. (ver o train ;:'&{::')&.> o i. f.av
|
||||
tie=. ver o train ;:'`'
|
||||
|
||||
indices=. (, $~ 1 -.~ $) o (train"0 o ((1 -: L.)S:1 # <S:1) o (tie&'') o fix :: ])
|
||||
f=. ((ver o train ;:'&{')) o indices o train f.av
|
||||
|
||||
'A B'=. 2 Fetch
|
||||
head=. (;:'<@:') {.~ 2 * 1 = #@[
|
||||
h=. train o (indices o train o (A f) (head , (B f)@] , < o an@[ , (;:'}]')c) ]) f.av
|
||||
|
||||
DropIfNB=. < o ('('"_ , ] , ')'"_) o ((}: ^: ('NB.' -: 3&{. o > o {:)) &. ;:)
|
||||
pipe=. ([ , ' o ' , ])&:>/ o |.
|
||||
|
||||
is=. ". o (, o ": o > , '=. ' , pipe o (DropIfNB;._2) o ". o ('0 ( : 0)'c)) f.av
|
||||
|
||||
NB.--------------------------------------------------------------------------------------
|
||||
|
||||
NB. Producing the verb simulate...
|
||||
|
||||
Note 0
|
||||
|
||||
NB. X and Y...
|
||||
N - Philosophers names
|
||||
C - Number of chronological events to simulate
|
||||
|
||||
NB. Local...
|
||||
A - Activity (0 - Thinking, 1 -eating, 2 - Thinking while queuing,)
|
||||
B - New activity
|
||||
T - Residual time left for the activity
|
||||
S - Starting time for the new activity
|
||||
Q - Queue
|
||||
U - Upper bound for the number of philosophers who can eat simultaneously
|
||||
P - Active philosopher
|
||||
E - Elapsed Time (only for information purposes)
|
||||
)
|
||||
|
||||
amend=. 0 (0 {:: ])`(<@:(1 {:: ]))`(2 {:: ])} ]
|
||||
|
||||
'N C A B T S Q U P E'=. 10 Fetch NB. 10 Boxes
|
||||
|
||||
thinktime=. _1 * ^. o ? o 0: NB. Exponentially distributed at a rate of one
|
||||
eattime =. _2 * ^. o ? o 0: NB. Exponentially distributed at a rate of one-half
|
||||
j=. ,&<
|
||||
|
||||
time=. (6j3 ": E) , ': 'c
|
||||
|
||||
start is
|
||||
(N Q)`((;: o N) j (''c)) h NB. Boxing the names, empty queue
|
||||
(A T)`((0:items j thinktime&>) o N) h NB. All start thinking
|
||||
(E U)`(0 ; <. o (2 %~ # o N)) h NB. Elapsed time 0, Upper bound
|
||||
[ echo o (time , 'All of them start thinking.'c)
|
||||
)
|
||||
|
||||
CanEat=. U > 1 +/ o = A NB. Can eat if there is a suitable place at the table
|
||||
|
||||
eat is
|
||||
T`(amend o ((S P T)f))h o (S`eattime h) NB. Eating time
|
||||
A`(amend o ((B P A)f))h o (B`1: h) NB. Activity: eating
|
||||
[ echo o (time , ' starts eating.' ,~ P {:: N)
|
||||
)
|
||||
|
||||
enqueue is
|
||||
T`(amend o ((S P T)f))h o (S`_:h) NB. Inactive until someone else ends eating
|
||||
A`(amend o ((B P A)f))h o (B`2:h) NB. Activity: thinking while queuing
|
||||
Q`(Q , P)h NB. Enqueuing
|
||||
[ echo o (time , ' starts waiting and thinking about hunger.' ,~ P {:: N)
|
||||
)
|
||||
|
||||
thinking=. enqueue`eat@.CanEat NB. Either enqueues or eats after thinking
|
||||
|
||||
dequeue is
|
||||
P`({. o Q)h NB. Activating the one in front of the queue
|
||||
eat NB. and starts eating
|
||||
Q`(}. o Q)h NB. dequeuing
|
||||
)
|
||||
|
||||
eating is NB. Thinks after eating
|
||||
T`(amend o ((S P T)f))h o (S`thinktime h) NB. Thinking time
|
||||
A`(amend o ((B P A)f))h o (B`0: h) NB. Activity: thinking
|
||||
[ echo o ( time , ' starts thinking.' ,~ P {:: N)
|
||||
dequeue ^: (1 <: # o Q) NB. Dequeuing a philosopher (if possible)
|
||||
)
|
||||
|
||||
update is
|
||||
E`(E + <./ o T)h NB. Updating the elapsed time
|
||||
T`((- <./)@:T) h NB. Updating the residual times
|
||||
P`(0 I. o = T) h NB. Setting the active philosopher
|
||||
thinking`eating@.((P { A)z) NB. Was thinking or eating?
|
||||
C`(1 -~ C) h NB. One chronological event completed
|
||||
)
|
||||
|
||||
simulate is NB. Discrete event simulation (dyadic verb)
|
||||
; NB. Linking the arguments (N C)
|
||||
,&(;:8$',') NB. Appending 8 local boxes (A B T S Q U P E)
|
||||
start
|
||||
update ^: (0 < C) ^: _ NB. Updating while events are less than C
|
||||
''c
|
||||
)
|
||||
|
||||
simulate=. simulate f.
|
||||
|
||||
NB. The simulation code is produced by the sentence,
|
||||
NB. 77 (-@:[ ]\ 5!:5@<@:]) 'simulate'
|
||||
113
Task/Dining-philosophers/Java/dining-philosophers.java
Normal file
113
Task/Dining-philosophers/Java/dining-philosophers.java
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package diningphilosophers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
enum PhilosopherState { Get, Eat, Pon }
|
||||
|
||||
class Fork {
|
||||
public static final int ON_TABLE = -1;
|
||||
static int instances = 0;
|
||||
public int id;
|
||||
public AtomicInteger holder = new AtomicInteger(ON_TABLE);
|
||||
|
||||
Fork() { id = instances++; }
|
||||
}
|
||||
|
||||
class Philosopher implements Runnable {
|
||||
static final int maxWaitMs = 100; // must be > 0
|
||||
static AtomicInteger token = new AtomicInteger(0);
|
||||
static int instances = 0;
|
||||
static Random rand = new Random();
|
||||
AtomicBoolean end = new AtomicBoolean(false);
|
||||
int id;
|
||||
PhilosopherState state = PhilosopherState.Get;
|
||||
Fork left;
|
||||
Fork right;
|
||||
int timesEaten = 0;
|
||||
|
||||
Philosopher() {
|
||||
id = instances++;
|
||||
left = Main.forks.get(id);
|
||||
right = Main.forks.get((id+1)%Main.philosopherCount);
|
||||
}
|
||||
|
||||
void sleep() { try { Thread.sleep(rand.nextInt(maxWaitMs)); }
|
||||
catch (InterruptedException ex) {} }
|
||||
|
||||
void waitForFork(Fork fork) {
|
||||
do {
|
||||
if (fork.holder.get() == Fork.ON_TABLE) {
|
||||
fork.holder.set(id); // my id shows I hold it
|
||||
return;
|
||||
} else { // someone still holds it
|
||||
sleep(); // check again later
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
do {
|
||||
if (state == PhilosopherState.Pon) { // all that pondering
|
||||
state = PhilosopherState.Get; // made me hungry
|
||||
} else { // ==PhilosopherState.Get
|
||||
if (token.get() == id) { // my turn now
|
||||
waitForFork(left);
|
||||
waitForFork(right); // Ah needs me some foahks!
|
||||
token.set((id+2)% Main.philosopherCount);
|
||||
state = PhilosopherState.Eat;
|
||||
timesEaten++;
|
||||
sleep(); // eat for a while
|
||||
left.holder.set(Fork.ON_TABLE);
|
||||
right.holder.set(Fork.ON_TABLE);
|
||||
state = PhilosopherState.Pon; // ponder for a while
|
||||
sleep();
|
||||
} else { // token.get() != id, so not my turn
|
||||
sleep();
|
||||
}
|
||||
}
|
||||
} while (!end.get());
|
||||
}
|
||||
}
|
||||
|
||||
public class Main {
|
||||
static final int philosopherCount = 5; // token +2 behavior good for odd #s
|
||||
static final int runSeconds = 15;
|
||||
static ArrayList<Fork> forks = new ArrayList<Fork>();
|
||||
static ArrayList<Philosopher> philosophers = new ArrayList<Philosopher>();
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0 ; i < philosopherCount ; i++) forks.add(new Fork());
|
||||
for (int i = 0 ; i < philosopherCount ; i++)
|
||||
philosophers.add(new Philosopher());
|
||||
for (Philosopher p : philosophers) new Thread(p).start();
|
||||
long endTime = System.currentTimeMillis() + (runSeconds * 1000);
|
||||
|
||||
do { // print status
|
||||
StringBuilder sb = new StringBuilder("|");
|
||||
|
||||
for (Philosopher p : philosophers) {
|
||||
sb.append(p.state.toString());
|
||||
sb.append("|"); // This is a snapshot at a particular
|
||||
} // instant. Plenty happens between.
|
||||
|
||||
sb.append(" |");
|
||||
|
||||
for (Fork f : forks) {
|
||||
int holder = f.holder.get();
|
||||
sb.append(holder==-1?" ":String.format("P%02d",holder));
|
||||
sb.append("|");
|
||||
}
|
||||
|
||||
System.out.println(sb.toString());
|
||||
try {Thread.sleep(1000);} catch (Exception ex) {}
|
||||
} while (System.currentTimeMillis() < endTime);
|
||||
|
||||
for (Philosopher p : philosophers) p.end.set(true);
|
||||
for (Philosopher p : philosophers)
|
||||
System.out.printf("P%02d: ate %,d times, %,d/sec\n",
|
||||
p.id, p.timesEaten, p.timesEaten/runSeconds);
|
||||
}
|
||||
}
|
||||
21
Task/Dining-philosophers/JoCaml/dining-philosophers-1.jocaml
Normal file
21
Task/Dining-philosophers/JoCaml/dining-philosophers-1.jocaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
let random_wait n = Unix.sleep (Random.int n);;
|
||||
let print s m = Printf.printf "philosopher %s is %s\n" s m; flush(stdout);;
|
||||
let will_eat s = print s "eating"; random_wait 10;;
|
||||
let will_think s = print s "thinking"; random_wait 20; print s "hungry";;
|
||||
|
||||
(* a,b,c,d,e are thinking philosophers; ah,bh,ch,dh,eh are the same philosophers when hungry;
|
||||
fab is the fork located between philosophers a and b; similarly for fbc, fcd, ... *)
|
||||
|
||||
def ah() & fab() & fea() = will_eat "Aristotle"; a() & fab() & fea()
|
||||
or bh() & fab() & fbc() = will_eat "Kant"; b() & fab() & fbc()
|
||||
or ch() & fbc() & fcd() = will_eat "Spinoza"; c() & fbc() & fcd()
|
||||
or dh() & fcd() & fde() = will_eat "Marx"; d() & fcd() & fde()
|
||||
or eh() & fde() & fea() = will_eat "Russell"; e() & fde() & fea()
|
||||
|
||||
and a() = will_think "Aristotle"; ah()
|
||||
and b() = will_think "Kant"; bh()
|
||||
and c() = will_think "Spinoza"; ch()
|
||||
and d() = will_think "Marx"; dh()
|
||||
and e() = will_think "Russell"; eh()
|
||||
;;
|
||||
spawn fab() & fbc() & fcd() & fde() & fea() & a() & b() & c() & d() & e();;
|
||||
47
Task/Dining-philosophers/JoCaml/dining-philosophers-2.jocaml
Normal file
47
Task/Dining-philosophers/JoCaml/dining-philosophers-2.jocaml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
let print s t m = Printf.printf "t=%d: philosopher %s is %s\n" t s m; flush(stdout);;
|
||||
let random_wait n = Unix.sleep (Random.int n);;
|
||||
|
||||
(* auxiliary function to keep track of time ticks, using integer seconds *)
|
||||
def ts () & counter(n) = counter(n) & reply n to ts
|
||||
or update_counter() & counter(n) = counter(n+1) & reply to update_counter
|
||||
and counter_sentinel() = Unix.sleep 1; update_counter(); counter_sentinel()
|
||||
;;
|
||||
spawn counter(0) & counter_sentinel();;
|
||||
|
||||
def stats(n, waited, maxwaited) & report_wait_time(m) =
|
||||
let (n', waited', maxwaited') = (n+1, waited+m, max maxwaited m) in
|
||||
Printf.printf "waiting average %f, max waited %d\n"
|
||||
(float_of_int waited' /. float_of_int n')
|
||||
maxwaited';
|
||||
flush(stdout);
|
||||
stats(n',waited',maxwaited') & reply () to report_wait_time
|
||||
;;
|
||||
|
||||
spawn stats(0,0,0);;
|
||||
|
||||
let eat s t = print s t "eating"; random_wait 10;;
|
||||
let think s = print s (ts()) "thinking"; random_wait 20;;
|
||||
|
||||
(* "p" will be a philosopher channel, to be defined later
|
||||
the messages ah, bh, ... do not need to be injected now. *)
|
||||
|
||||
let will_eat s t = let t' = ts() in report_wait_time(t'-t); eat s t';;
|
||||
|
||||
def ah(t,p) & fab() & fea() = will_eat "Aristotle" t; p() & fab() & fea()
|
||||
or bh(t,p) & fab() & fbc() = will_eat "Kant" t; p() & fab() & fbc()
|
||||
or ch(t,p) & fbc() & fcd() = will_eat "Spinoza" t; p() & fbc() & fcd()
|
||||
or dh(t,p) & fcd() & fde() = will_eat "Marx" t; p() & fcd() & fde()
|
||||
or eh(t,p) & fde() & fea() = will_eat "Russell" t; p() & fde() & fea()
|
||||
;;
|
||||
|
||||
spawn fab() & fbc() & fcd() & fde() & fea();;
|
||||
|
||||
(* define the thinking -> hungry transitions using local philosophers, and inject the philosophers *)
|
||||
List.map
|
||||
(fun (h,s) -> def p() = think s; let t = ts() in print s t "hungry"; h(t,p) in spawn p())
|
||||
[(ah,"Aristotle"); (bh,"Kant"); (ch,"Spinoza"); (dh,"Marx"); (eh,"Russell")]
|
||||
;;
|
||||
(* this replaces repetitive code such as that shown in the previous solution *)
|
||||
|
||||
(* now we need to wait and do nothing; nobody will be able to inject godot() *)
|
||||
def wait_forever() & godot() = reply () to wait_forever in wait_forever();;
|
||||
77
Task/Dining-philosophers/JoCaml/dining-philosophers-3.jocaml
Normal file
77
Task/Dining-philosophers/JoCaml/dining-philosophers-3.jocaml
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/jocamlrun jocaml
|
||||
|
||||
(* eating and thinking between 0 and this-1 *)
|
||||
let eating_max_interval = 10;;
|
||||
let thinking_max_interval = 10;;
|
||||
let number_of_philosophers = 5;;
|
||||
let random_wait n = Unix.sleep (Random.int n);;
|
||||
|
||||
(* counter for unique timestamp, not related to time in seconds *)
|
||||
def get_current_time () & unique_ts_counter(n) = unique_ts_counter(n+1) & reply n to get_current_time;;
|
||||
spawn unique_ts_counter(0);;
|
||||
|
||||
(* functions that wait and print diagnostics *)
|
||||
let name i = List.nth ["Aristotle"; "Kant"; "Spinoza"; "Marx"; "Russell"] i;;
|
||||
let message i m = Printf.printf "philosopher %s is %s\n" (name i) m; flush(stdout);;
|
||||
let eat i = message i "eating"; random_wait eating_max_interval;;
|
||||
let think i = message i "thinking"; random_wait thinking_max_interval;;
|
||||
|
||||
type philosopher_state_t = Eating | Hungry of int | Thinking;;
|
||||
|
||||
(* initial states *)
|
||||
let states = Array.make number_of_philosophers Thinking;;
|
||||
(* one philosopher's processes *)
|
||||
let make_philosopher i got_hungry done_eating =
|
||||
def hungry() & forks() = eat i ; done_eating(i) & thinking()
|
||||
and thinking() = think i; got_hungry(i) & hungry()
|
||||
in spawn thinking(); forks
|
||||
;;
|
||||
|
||||
(* deciding who will eat first *)
|
||||
let next_phil i = (i+1) mod number_of_philosophers;;
|
||||
let prev_phil i = (number_of_philosophers+i-1) mod number_of_philosophers;;
|
||||
let is_hungry p = match p with
|
||||
| Hungry h -> true
|
||||
| _ -> false;;
|
||||
let not_eating p = match p with
|
||||
| Eating -> false
|
||||
| _ -> true;;
|
||||
let is_more_hungry p q = match q with
|
||||
| Hungry hj -> (
|
||||
match p with
|
||||
| Hungry hi -> hi <= hj
|
||||
| _ -> false
|
||||
)
|
||||
| _ -> true
|
||||
;;
|
||||
|
||||
let may_eat_first i =
|
||||
is_hungry states.(i)
|
||||
&& not_eating states.(next_phil i) && not_eating states.(prev_phil i)
|
||||
&& is_more_hungry states.(i) states.(next_phil i)
|
||||
&& is_more_hungry states.(i) states.(prev_phil i);;
|
||||
|
||||
let decide_eating i =
|
||||
if (may_eat_first i) then (states.(i) <- Eating; true)
|
||||
else false;;
|
||||
|
||||
def waiter(all_forks) & got_hungry(i) =
|
||||
states.(i) <- Hungry (get_current_time());
|
||||
let will_eat = decide_eating i in (
|
||||
waiter(all_forks) & (if will_eat then all_forks.(i)() else 0)
|
||||
)
|
||||
or waiter(all_forks) & done_eating(i) =
|
||||
states.(i) <- Thinking;
|
||||
let next_will_eat = decide_eating (next_phil i) in
|
||||
let prev_will_eat = decide_eating (prev_phil i) in (
|
||||
waiter(all_forks)
|
||||
& (if next_will_eat then all_forks.(next_phil i)() else 0)
|
||||
& (if prev_will_eat then all_forks.(prev_phil i)() else 0)
|
||||
);;
|
||||
|
||||
let all_forks = Array.init number_of_philosophers (fun i -> make_philosopher i got_hungry done_eating)
|
||||
in spawn waiter(all_forks);;
|
||||
|
||||
(* now we need to wait and do nothing; nobody will be able to inject godot() *)
|
||||
|
||||
def wait_forever() & godot() = reply () to wait_forever in wait_forever();;
|
||||
83
Task/Dining-philosophers/Julia/dining-philosophers.julia
Normal file
83
Task/Dining-philosophers/Julia/dining-philosophers.julia
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
mutable struct Philosopher
|
||||
name::String
|
||||
hungry::Bool
|
||||
righthanded::Bool
|
||||
rightforkheld::Channel
|
||||
leftforkheld::Channel
|
||||
function Philosopher(name, leftfork, rightfork)
|
||||
this = new()
|
||||
this.name = name
|
||||
this.hungry = rand([false, true]) # not specified so start as either
|
||||
this.righthanded = (name == "Aristotle") ? false : true
|
||||
this.leftforkheld = leftfork
|
||||
this.rightforkheld = rightfork
|
||||
this
|
||||
end
|
||||
end
|
||||
|
||||
mutable struct FiveForkTable
|
||||
fork51::Channel
|
||||
fork12::Channel
|
||||
fork23::Channel
|
||||
fork34::Channel
|
||||
fork45::Channel
|
||||
function FiveForkTable()
|
||||
this = new()
|
||||
this.fork51 = Channel(1); put!(this.fork51, "fork") # start with one fork per channel
|
||||
this.fork12 = Channel(1); put!(this.fork12, "fork")
|
||||
this.fork23 = Channel(1); put!(this.fork23, "fork")
|
||||
this.fork34 = Channel(1); put!(this.fork34, "fork")
|
||||
this.fork45 = Channel(1); put!(this.fork45, "fork")
|
||||
this
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
table = FiveForkTable();
|
||||
tasks = [Philosopher("Aristotle", table.fork12, table.fork51),
|
||||
Philosopher("Kant", table.fork23, table.fork12),
|
||||
Philosopher("Spinoza", table.fork34, table.fork23),
|
||||
Philosopher("Marx", table.fork45, table.fork34),
|
||||
Philosopher("Russell", table.fork51, table.fork45)]
|
||||
|
||||
function dine(t,p)
|
||||
if p.righthanded
|
||||
take!(p.rightforkheld); println("$(p.name) takes right fork")
|
||||
take!(p.leftforkheld); println("$(p.name) takes left fork")
|
||||
else
|
||||
take!(p.leftforkheld); println("$(p.name) takes left fork")
|
||||
take!(p.rightforkheld); println("$(p.name) takes right fork")
|
||||
end
|
||||
end
|
||||
|
||||
function leavetothink(t, p)
|
||||
put!(p.rightforkheld, "fork"); println("$(p.name) puts down right fork")
|
||||
put!(p.leftforkheld, "fork"); println("$(p.name) puts down left fork")
|
||||
end
|
||||
|
||||
contemplate(t) = sleep(t)
|
||||
|
||||
function dophil(p, t, fullaftersecs=2.0, hungryaftersecs=10.0)
|
||||
while true
|
||||
if p.hungry
|
||||
println("$(p.name) is hungry")
|
||||
dine(table, p)
|
||||
sleep(fullaftersecs)
|
||||
p.hungry = false
|
||||
leavetothink(t, p)
|
||||
else
|
||||
println("$(p.name) is out of the dining room for now.")
|
||||
contemplate(hungryaftersecs)
|
||||
p.hungry = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function runall(tasklist)
|
||||
for p in tasklist
|
||||
@async dophil(p, table)
|
||||
end
|
||||
while true begin sleep(5) end end
|
||||
end
|
||||
|
||||
runall(tasks)
|
||||
58
Task/Dining-philosophers/Kotlin/dining-philosophers.kotlin
Normal file
58
Task/Dining-philosophers/Kotlin/dining-philosophers.kotlin
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// Version 1.2.31
|
||||
|
||||
import java.util.Random
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
val rand = Random()
|
||||
|
||||
class Fork(val name: String) {
|
||||
val lock = ReentrantLock()
|
||||
|
||||
fun pickUp(philosopher: String) {
|
||||
lock.lock()
|
||||
println(" $philosopher picked up $name")
|
||||
}
|
||||
|
||||
fun putDown(philosopher: String) {
|
||||
lock.unlock()
|
||||
println(" $philosopher put down $name")
|
||||
}
|
||||
}
|
||||
|
||||
class Philosopher(val pname: String, val f1: Fork, val f2: Fork) : Thread() {
|
||||
override fun run() {
|
||||
(1..20).forEach {
|
||||
println("$pname is hungry")
|
||||
f1.pickUp(pname)
|
||||
f2.pickUp(pname)
|
||||
println("$pname is eating bite $it")
|
||||
Thread.sleep(rand.nextInt(300) + 100L)
|
||||
f2.putDown(pname)
|
||||
f1.putDown(pname)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun diningPhilosophers(names: List<String>) {
|
||||
val size = names.size
|
||||
val forks = List(size) { Fork("Fork ${it + 1}") }
|
||||
val philosophers = mutableListOf<Philosopher>()
|
||||
names.forEachIndexed { i, n ->
|
||||
var i1 = i
|
||||
var i2 = (i + 1) % size
|
||||
if (i2 < i1) {
|
||||
i1 = i2
|
||||
i2 = i
|
||||
}
|
||||
val p = Philosopher(n, forks[i1], forks[i2])
|
||||
p.start()
|
||||
philosophers.add(p)
|
||||
}
|
||||
philosophers.forEach { it.join() }
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val names = listOf("Aristotle", "Kant", "Spinoza", "Marx", "Russell")
|
||||
diningPhilosophers(names)
|
||||
}
|
||||
156
Task/Dining-philosophers/Logtalk/dining-philosophers.logtalk
Normal file
156
Task/Dining-philosophers/Logtalk/dining-philosophers.logtalk
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
:- category(chopstick).
|
||||
|
||||
% chopstick actions (picking up and putting down) are synchronized using a notification
|
||||
% such that a chopstick can only be handled by a single philosopher at a time:
|
||||
|
||||
:- public(pick_up/0).
|
||||
pick_up :-
|
||||
threaded_wait(available).
|
||||
|
||||
:- public(put_down/0).
|
||||
put_down :-
|
||||
threaded_notify(available).
|
||||
|
||||
:- end_category.
|
||||
|
||||
|
||||
:- object(cs1,
|
||||
imports(chopstick)).
|
||||
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(cs2,
|
||||
imports(chopstick)).
|
||||
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(cs3,
|
||||
imports(chopstick)).
|
||||
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(cs4,
|
||||
imports(chopstick)).
|
||||
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(cs5,
|
||||
imports(chopstick)).
|
||||
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- category(philosopher).
|
||||
|
||||
:- public(left_chopstick/1).
|
||||
:- public(right_chopstick/1).
|
||||
:- public(run/2).
|
||||
|
||||
:- private(message/1).
|
||||
:- synchronized(message/1).
|
||||
|
||||
:- uses(random, [random/3]).
|
||||
|
||||
run(0, _) :-
|
||||
this(Philosopher),
|
||||
message([Philosopher, ' terminated.']).
|
||||
|
||||
run(Count, MaxTime) :-
|
||||
Count > 0,
|
||||
think(MaxTime),
|
||||
eat(MaxTime),
|
||||
Count2 is Count - 1,
|
||||
run(Count2, MaxTime).
|
||||
|
||||
think(MaxTime):-
|
||||
this(Philosopher),
|
||||
random(1, MaxTime, ThinkTime),
|
||||
message(['Philosopher ', Philosopher, ' thinking for ', ThinkTime, ' seconds.']),
|
||||
thread_sleep(ThinkTime).
|
||||
|
||||
eat(MaxTime):-
|
||||
this(Philosopher),
|
||||
random(1, MaxTime, EatTime),
|
||||
::left_chopstick(LeftStick),
|
||||
::right_chopstick(RightStick),
|
||||
LeftStick::pick_up,
|
||||
RightStick::pick_up,
|
||||
message(['Philosopher ', Philosopher, ' eating for ', EatTime, ' seconds with chopsticks ', LeftStick, ' and ', RightStick, '.']),
|
||||
thread_sleep(EatTime),
|
||||
::LeftStick::put_down,
|
||||
::RightStick::put_down.
|
||||
|
||||
% writing a message needs to be synchronized as it's accomplished
|
||||
% using a combination of individual write/1 and nl/0 calls:
|
||||
message([]) :-
|
||||
nl,
|
||||
flush_output.
|
||||
message([Atom| Atoms]) :-
|
||||
write(Atom),
|
||||
message(Atoms).
|
||||
|
||||
:- end_category.
|
||||
|
||||
|
||||
:- object(aristotle,
|
||||
imports(philosopher)).
|
||||
|
||||
left_chopstick(cs1).
|
||||
right_chopstick(cs2).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(kant,
|
||||
imports(philosopher)).
|
||||
|
||||
left_chopstick(cs2).
|
||||
right_chopstick(cs3).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(spinoza,
|
||||
imports(philosopher)).
|
||||
|
||||
left_chopstick(cs3).
|
||||
right_chopstick(cs4).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(marx,
|
||||
imports(philosopher)).
|
||||
|
||||
left_chopstick(cs4).
|
||||
right_chopstick(cs5).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(russell,
|
||||
imports(philosopher)).
|
||||
|
||||
left_chopstick(cs1). % change order so that the chopsticks are picked
|
||||
right_chopstick(cs5). % in different order from the other philosophers
|
||||
|
||||
:- end_object.
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
Module Dining_philosophers (whichplan) {
|
||||
Form 80, 32
|
||||
Const MayChangePick=Random(True, False)
|
||||
dim energy(1 to 5)=50
|
||||
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"
|
||||
Print Part $(1), time_to_appear
|
||||
Print under
|
||||
}
|
||||
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
|
||||
}
|
||||
PlaceAnyFork=lambda RoundTable (ph as philosopher, &ForkL, &ForkR) -> {
|
||||
If ForkL=Fork then Return RoundTable, (ph+4) mod 5:=Fork : ForkL=NoFork
|
||||
If ForkR=Fork Then Return RoundTable, ph mod 5:=Fork : ForkR=NoFork
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
if energy(f)<1 then {
|
||||
call PlaceAnyFork(f, ForkL, ForkR)
|
||||
energy(f)=0
|
||||
Page$=format$("{0::-12} - ",tick-basetick)+eval$(f)+" - Die"+nl$
|
||||
thread this erase
|
||||
} else {
|
||||
Page$=format$("{0::-12} - ",tick-basetick)+eval$(f)
|
||||
Page$=if$(ForkL=Nofork or ForkR=Nofork->" thinking", " eating"+str$(eatcount))
|
||||
Page$=if$(R->"- R", " - L")+nl$
|
||||
}
|
||||
if not think then
|
||||
{ \\ a block always run blocking all other threads
|
||||
energy(f)++
|
||||
eatcount--
|
||||
if eatcount>0 then exit
|
||||
Call PlaceForks(f) : ForkL=Nofork:ForkR=NoFork
|
||||
eatcount=random(4,8)
|
||||
if MayChangePick then R=random(-1,0)
|
||||
think=true :thread this interval time_to_think*random(1,5)
|
||||
}
|
||||
else.if energy(f)>70 or critical>5 then
|
||||
{
|
||||
call PlaceAnyFork(f, &ForkL, &ForkR)
|
||||
if energy(f)>70 then energy(f)=60
|
||||
}
|
||||
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 energy(f)--
|
||||
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 else energy(f)--
|
||||
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 {
|
||||
\\ this executed on thread execution object
|
||||
static f=eval(m), think=true, ForkL=NoFork
|
||||
static ForkR=NoFork, eatcount=random(2,5)
|
||||
static R=-1
|
||||
if MayChangePick then R=Random(-1,0)
|
||||
}
|
||||
}
|
||||
cls ,5 ' 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
|
||||
MaxCritical=0
|
||||
Main.Task 1000/4 {
|
||||
{ \\ a block always run blocking all other threads
|
||||
cls
|
||||
Print Part $(1),$("####;\D\I\E;\D\I\E"),energy()
|
||||
Print Under
|
||||
Print "Table:"
|
||||
Call ShowTable()
|
||||
if noforks() then critical++ else critical=0
|
||||
MaxCritical=if(MaxCritical<critical->critical,MaxCritical)
|
||||
Print "noforks on table counter:";critical, "Max:";MaxCritical
|
||||
Print #-2,Page$
|
||||
Doc$=Page$
|
||||
Clear Page$
|
||||
}
|
||||
if critical>40 or keypress(1) then exit
|
||||
}
|
||||
threads erase
|
||||
Clipboard Doc$
|
||||
}
|
||||
Dining_philosophers Random(1,2)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
names = <|1 -> "Aristotle", 2 -> "Kant", 3 -> "Spinoza", 4 -> "Marx", 5 -> "Russell"|>;
|
||||
n = Length[names];
|
||||
rp := Pause[RandomReal[4]];
|
||||
PrintTemporary[Dynamic[Array[forks, n]]];
|
||||
Clear[forks]; forks[_] := Null;
|
||||
With[{nf = n},
|
||||
ParallelDo[
|
||||
With[{i1 = i, i2 = Mod[i + 1, nf, 1]},
|
||||
Do[Print[names[i], " thinking"]; rp; Print[names[i], " hungry"];
|
||||
CriticalSection[{forks[i1], forks[i2]},
|
||||
Print[names[i], " eating"]; rp],
|
||||
{2}]],
|
||||
{i, nf}]];
|
||||
101
Task/Dining-philosophers/Modula-3/dining-philosophers.mod3
Normal file
101
Task/Dining-philosophers/Modula-3/dining-philosophers.mod3
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
MODULE DiningPhilosophers EXPORTS Main;
|
||||
|
||||
IMPORT IO, Random, Thread;
|
||||
|
||||
CONST
|
||||
|
||||
PartySize = 5; (* modify for more/fewer philosophers *)
|
||||
|
||||
TYPE
|
||||
|
||||
Closure = Thread.Closure OBJECT
|
||||
(* thread information *)
|
||||
which: [1..PartySize]; (* identifies the thread *)
|
||||
OVERRIDES
|
||||
apply := Live; (* procedure to execute *)
|
||||
END;
|
||||
|
||||
VAR
|
||||
|
||||
(* how long to eat/think *)
|
||||
random: Random.T;
|
||||
|
||||
(* controls access to resources *)
|
||||
test := NEW(MUTEX);
|
||||
forks := NEW(Thread.Condition); (* condition variable, used for signaling *)
|
||||
forkAvailable := ARRAY[1..PartySize] OF BOOLEAN {
|
||||
TRUE, TRUE, TRUE, TRUE, TRUE
|
||||
};
|
||||
(* the philosophers/tasks *)
|
||||
thread: ARRAY[1..PartySize] OF Thread.T;
|
||||
name := ARRAY[1..PartySize] OF TEXT {
|
||||
"Aristotle", "Kant", "Spinoza", "Marx", "Russell"
|
||||
};
|
||||
|
||||
PROCEDURE PlaceAvailable(): CARDINAL =
|
||||
(*
|
||||
Determines whether a place is available at the table.
|
||||
If so, returns the place number. Otherwise, returns 0.
|
||||
We consider a place available if and only if *both* forks are free.
|
||||
*)
|
||||
BEGIN
|
||||
FOR i := 1 TO PartySize DO
|
||||
IF forkAvailable[i] AND forkAvailable[((i+1) MOD PartySize) + 1] THEN
|
||||
RETURN i;
|
||||
END;
|
||||
END;
|
||||
RETURN 0;
|
||||
END PlaceAvailable;
|
||||
|
||||
PROCEDURE Live(philosopher: Closure): REFANY =
|
||||
(* philosophers eat, sleep, ... and that's about it *)
|
||||
VAR
|
||||
place: CARDINAL;
|
||||
BEGIN
|
||||
WITH which = philosopher.which DO
|
||||
WHILE TRUE DO
|
||||
(* first make sure a place is available: both forks must be free! *)
|
||||
LOCK test DO
|
||||
place := PlaceAvailable();
|
||||
(* if not, release mutex and use condition variable to wait for one *)
|
||||
WHILE place = 0 DO
|
||||
IO.Put(name[which]); IO.Put(" starving!\n");
|
||||
Thread.Wait(test, forks);
|
||||
(* in Modula-3 we arrive here only if we have the lock again *)
|
||||
place := PlaceAvailable();
|
||||
END;
|
||||
(* a place has come available! seize the forks while mutex is locked *)
|
||||
forkAvailable[place] := FALSE;
|
||||
forkAvailable[(place MOD PartySize) + 1] := FALSE;
|
||||
IO.Put(name[which]); IO.Put(" eating at place "); IO.PutInt(place);
|
||||
IO.PutChar('\n');
|
||||
END;
|
||||
Thread.Pause(FLOAT(random.integer(1,3), LONGREAL));
|
||||
(* put down the forks *)
|
||||
forkAvailable[place] := TRUE;
|
||||
forkAvailable[(place MOD PartySize) + 1] := TRUE;
|
||||
Thread.Signal(forks); (* signal the condition variable *)
|
||||
LOCK test DO
|
||||
IO.Put(name[which]); IO.Put(" thinking\n");
|
||||
END;
|
||||
Thread.Pause(FLOAT(random.integer(1,3), LONGREAL));
|
||||
END; (* WHILE *)
|
||||
END; (* WITH *)
|
||||
RETURN NIL;
|
||||
END Live;
|
||||
|
||||
BEGIN
|
||||
random := NEW(Random.Default).init();
|
||||
(* bring philosophers to life *)
|
||||
FOR i := 1 TO PartySize DO
|
||||
thread[i] := Thread.Fork(NEW(Closure, apply := Live, which := i));
|
||||
END;
|
||||
(*
|
||||
We need to wait, otherwise the program will terminate,
|
||||
and the philosophers with it. Technically we could wait
|
||||
for just one philosopher, but in the interest of symmetry...
|
||||
*)
|
||||
FOR i := 1 TO PartySize DO
|
||||
EVAL Thread.Join(thread[i]);
|
||||
END;
|
||||
END DiningPhilosophers.
|
||||
47
Task/Dining-philosophers/Nim/dining-philosophers.nim
Normal file
47
Task/Dining-philosophers/Nim/dining-philosophers.nim
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import threadpool, locks, math, os, random
|
||||
# to call randomize() as a seed, need to import random module
|
||||
randomize()
|
||||
|
||||
type Philosopher = ref object
|
||||
name: string
|
||||
food: string
|
||||
forkLeft, forkRight: int
|
||||
|
||||
const
|
||||
n = 5
|
||||
names = ["Aristotle", "Kant", "Spinoza", "Marx", "Russell"]
|
||||
foods = [" rat poison", " cockroaches", " dog food", " lemon-curd toast", " baked worms"]
|
||||
|
||||
var
|
||||
forks: array[n, Lock]
|
||||
phils: array[n, Philosopher]
|
||||
threads: array[n, Thread[Philosopher]]
|
||||
|
||||
proc run(p: Philosopher) {.thread.} =
|
||||
# random deprecated, use rand(x .. y)
|
||||
sleep rand(1..10) * 500
|
||||
echo p.name, " is hungry."
|
||||
|
||||
acquire forks[min(p.forkLeft, p.forkRight)]
|
||||
sleep rand(1..5) * 500
|
||||
acquire forks[max(p.forkLeft, p.forkRight)]
|
||||
|
||||
echo p.name, " starts eating", p.food, "."
|
||||
sleep rand(1..10) * 500
|
||||
|
||||
echo p.name, " finishes eating", p.food, " and leaves to think."
|
||||
|
||||
release forks[p.forkLeft]
|
||||
release forks[p.forkRight]
|
||||
|
||||
for i in 0..<n:
|
||||
initLock forks[i]
|
||||
phils[i] = Philosopher(
|
||||
name: names[i],
|
||||
food: foods[rand(0 .. n) mod n],
|
||||
forkLeft: i,
|
||||
forkRight: (i + 1) mod n
|
||||
)
|
||||
createThread(threads[i], run, phils[i])
|
||||
|
||||
joinThreads(threads)
|
||||
101
Task/Dining-philosophers/OxygenBasic/dining-philosophers.basic
Normal file
101
Task/Dining-philosophers/OxygenBasic/dining-philosophers.basic
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
'=========================
|
||||
class RoundTableWith5Seats
|
||||
'=========================
|
||||
|
||||
% hungry 0
|
||||
% beingUsed 1
|
||||
% putDown 0
|
||||
% empty 0
|
||||
|
||||
sys fork[5], plate[5],chair[5],philosopher[5]
|
||||
sys first
|
||||
|
||||
method AddPasta() as sys
|
||||
function rand() as sys
|
||||
static seed=0x12345678
|
||||
mov eax,seed
|
||||
rol eax,7
|
||||
mul seed
|
||||
xor eax,0x5335ABD9
|
||||
mov seed,eax
|
||||
return seed
|
||||
end function
|
||||
return 4+(rand() and 15)
|
||||
end method
|
||||
|
||||
method dine()
|
||||
first++ 'PRIORITY DINER
|
||||
if first>5 then first-=5
|
||||
for i=1 to 5
|
||||
kl=first+i-1
|
||||
kr=first+i
|
||||
if kl>5 then kl-=5
|
||||
if kr>5 then kr-=5
|
||||
if philosopher(kl) = hungry then
|
||||
if not fork(kl) or fork(kr) = beingUsed then
|
||||
plate(kl) = AddPasta()
|
||||
fork(kl)=beingUsed
|
||||
fork(kr)=beingUsed
|
||||
end if
|
||||
end if
|
||||
'
|
||||
next
|
||||
'
|
||||
for kl=1 to 5
|
||||
kr=kl+1 : if kr>5 then kr-=5
|
||||
if plate(kl)
|
||||
philosopher(kl)+=1 'PHILOSOPHER DINING
|
||||
--plate(kl)
|
||||
if plate(kl)=empty
|
||||
fork(kl)=PutDown
|
||||
fork(kr)=PutDown
|
||||
end if
|
||||
else
|
||||
if philosopher(kl)>0
|
||||
--philosopher(kl) 'PHILOSOPHER THINKING
|
||||
end if
|
||||
end if
|
||||
next
|
||||
'
|
||||
end method
|
||||
|
||||
method show() as string
|
||||
cr=chr(13)+chr(10) : tab=chr(9)
|
||||
pr="philos" tab "activity" tab "plate" tab "fork L" tab "fork R" cr cr
|
||||
for i=1 to 5
|
||||
j=i+1 : if j>5 then j-=5
|
||||
if plate(i)=0 then
|
||||
if philosopher(i)=0 then
|
||||
act="waiting"
|
||||
else
|
||||
act="thinks"
|
||||
end if
|
||||
else
|
||||
act="dining"
|
||||
end if
|
||||
'
|
||||
pr+=i tab act tab plate(i) tab fork(i) tab fork(j) cr
|
||||
next
|
||||
return pr
|
||||
end method
|
||||
|
||||
end class
|
||||
|
||||
'TEST
|
||||
'====
|
||||
|
||||
RoundTableWith5Seats Sopho
|
||||
for i=1 to 100
|
||||
Sopho.dine
|
||||
next
|
||||
|
||||
print Sopho.show
|
||||
'putfile "s.txt",Sopho.show
|
||||
|
||||
'philos action plate fork L fork R
|
||||
'
|
||||
'1 waiting 0 0 1
|
||||
'2 dining 8 1 1
|
||||
'3 thinks 0 1 1
|
||||
'4 dining 8 1 1
|
||||
'5 thinks 0 1 0
|
||||
117
Task/Dining-philosophers/Oz/dining-philosophers.oz
Normal file
117
Task/Dining-philosophers/Oz/dining-philosophers.oz
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
declare
|
||||
Philosophers = [aristotle kant spinoza marx russell]
|
||||
|
||||
proc {Start}
|
||||
Forks = {MakeList {Length Philosophers}}
|
||||
in
|
||||
{ForAll Forks NewFork}
|
||||
for
|
||||
Name in Philosophers
|
||||
LeftFork in Forks
|
||||
RightFork in {RightShift Forks}
|
||||
do
|
||||
thread
|
||||
{Philosopher Name LeftFork RightFork}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
proc {Philosopher Name LeftFork RightFork}
|
||||
for do
|
||||
{ShowInfo Name#" is hungry."}
|
||||
|
||||
{TakeForks [LeftFork RightFork]}
|
||||
{ShowInfo Name#" got forks."}
|
||||
{WaitRandom}
|
||||
{ReleaseFork LeftFork}
|
||||
{ReleaseFork RightFork}
|
||||
|
||||
{ShowInfo Name#" is thinking."}
|
||||
{WaitRandom}
|
||||
end
|
||||
end
|
||||
|
||||
proc {WaitRandom}
|
||||
{Delay 1000 + {OS.rand} mod 4000} %% 1-5 seconds
|
||||
end
|
||||
|
||||
proc {TakeForks Forks}
|
||||
{ForAll Forks WaitForFork}
|
||||
case {TryAtomically proc {$}
|
||||
{ForAll Forks TakeFork}
|
||||
end}
|
||||
of true then
|
||||
{ForAll Forks InitForkNotifier}
|
||||
[] false then
|
||||
{TakeForks Forks}
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
%% Fork type
|
||||
%%
|
||||
|
||||
%% A fork is a mutable reference to a pair
|
||||
fun {NewFork}
|
||||
{NewCell
|
||||
unit(taken:_ %% a fork is taken by setting this value to a unique value
|
||||
notify:unit %% to wait for a taken fork
|
||||
)}
|
||||
end
|
||||
|
||||
proc {TakeFork F}
|
||||
(@F).taken = {NewName}
|
||||
end
|
||||
|
||||
proc {InitForkNotifier F}
|
||||
%% we cannot do this in TakeFork
|
||||
%% because side effect are not allowed in subordinate spaces
|
||||
New Old
|
||||
in
|
||||
{Exchange F Old New}
|
||||
New = unit(taken:Old.taken notify:_)
|
||||
end
|
||||
|
||||
proc {ReleaseFork F}
|
||||
New Old
|
||||
in
|
||||
{Exchange F Old New}
|
||||
New = unit(taken:_ notify:unit)
|
||||
Old.notify = unit %% notify waiters
|
||||
end
|
||||
|
||||
proc {WaitForFork F}
|
||||
{Wait (@F).notify} %% returns immediatly if fork is free, otherwise blocks
|
||||
end
|
||||
|
||||
%%
|
||||
%% Helpers
|
||||
%%
|
||||
|
||||
%% Implements transactions on data flow variables
|
||||
%% with computation spaces. Returns success.
|
||||
fun {TryAtomically P}
|
||||
try
|
||||
S = {Space.new
|
||||
proc {$ Sync}
|
||||
{P}
|
||||
Sync = unit
|
||||
end}
|
||||
in
|
||||
{Space.askVerbose S} \= failed = true
|
||||
{Wait {Space.merge S}}
|
||||
true
|
||||
catch _ then
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
fun {RightShift Xs} %% circular
|
||||
case Xs of nil then nil
|
||||
else {Append Xs.2 [Xs.1]}
|
||||
end
|
||||
end
|
||||
|
||||
ShowInfo = System.showInfo
|
||||
in
|
||||
{Start}
|
||||
101
Task/Dining-philosophers/Pascal/dining-philosophers-1.pas
Normal file
101
Task/Dining-philosophers/Pascal/dining-philosophers-1.pas
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
program dining_philosophers;
|
||||
{$mode objfpc}{$H+}
|
||||
uses
|
||||
{$IFDEF UNIX}
|
||||
cthreads,
|
||||
{$ENDIF}
|
||||
Classes, SysUtils, SyncObjs;
|
||||
const
|
||||
PHIL_COUNT = 5;
|
||||
LIFESPAN = 7;
|
||||
DELAY_RANGE = 950;
|
||||
DELAY_LOW = 50;
|
||||
PHIL_NAMES: array[1..PHIL_COUNT] of string = ('Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell');
|
||||
type
|
||||
TFork = TCriticalSection;
|
||||
TPhilosopher = class;
|
||||
var
|
||||
Forks: array[1..PHIL_COUNT] of TFork;
|
||||
Philosophers: array[1..PHIL_COUNT] of TPhilosopher;
|
||||
type
|
||||
TPhilosopher = class(TThread)
|
||||
private
|
||||
FName: string;
|
||||
FFirstFork, FSecondFork: TFork;
|
||||
protected
|
||||
procedure Execute; override;
|
||||
public
|
||||
constructor Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
end;
|
||||
|
||||
procedure TPhilosopher.Execute;
|
||||
var
|
||||
LfSpan: Integer = LIFESPAN;
|
||||
begin
|
||||
while LfSpan > 0 do
|
||||
begin
|
||||
Dec(LfSpan);
|
||||
WriteLn(FName, ' sits down at the table');
|
||||
FFirstFork.Acquire;
|
||||
FSecondFork.Acquire;
|
||||
WriteLn(FName, ' eating');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
FSecondFork.Release;
|
||||
FFirstFork.Release;
|
||||
WriteLn(FName, ' is full and leaves the table');
|
||||
if LfSpan = 0 then
|
||||
continue;
|
||||
WriteLn(FName, ' thinking');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
WriteLn(FName, ' is hungry');
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TPhilosopher.Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
begin
|
||||
inherited Create(True);
|
||||
FName := aName;
|
||||
if aForkIdx1 < aForkIdx2 then
|
||||
begin
|
||||
FFirstFork := Forks[aForkIdx1];
|
||||
FSecondFork := Forks[aForkIdx2];
|
||||
end
|
||||
else
|
||||
begin
|
||||
FFirstFork := Forks[aForkIdx2];
|
||||
FSecondFork := Forks[aForkIdx1];
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure DinnerBegin;
|
||||
var
|
||||
I: Integer;
|
||||
Phil: TPhilosopher;
|
||||
begin
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Forks[I] := TFork.Create;
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Philosophers[I] := TPhilosopher.Create(PHIL_NAMES[I], I, Succ(I mod PHIL_COUNT));
|
||||
for Phil in Philosophers do
|
||||
Phil.Start;
|
||||
end;
|
||||
|
||||
procedure WaitForDinnerOver;
|
||||
var
|
||||
Phil: TPhilosopher;
|
||||
Fork: TFork;
|
||||
begin
|
||||
for Phil in Philosophers do
|
||||
begin
|
||||
Phil.WaitFor;
|
||||
Phil.Free;
|
||||
end;
|
||||
for Fork in Forks do
|
||||
Fork.Free;
|
||||
end;
|
||||
|
||||
begin
|
||||
Randomize;
|
||||
DinnerBegin;
|
||||
WaitForDinnerOver;
|
||||
end.
|
||||
115
Task/Dining-philosophers/Pascal/dining-philosophers-2.pas
Normal file
115
Task/Dining-philosophers/Pascal/dining-philosophers-2.pas
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
program dining_philosophers2;
|
||||
{$mode objfpc}{$H+}
|
||||
uses
|
||||
{$IFDEF UNIX}
|
||||
cthreads,
|
||||
{$ENDIF}
|
||||
Classes, SysUtils, SyncObjs;
|
||||
const
|
||||
PHIL_COUNT = 5;
|
||||
LIFESPAN = 7;
|
||||
DELAY_RANGE = 950;
|
||||
DELAY_LOW = 50;
|
||||
PHIL_NAMES: array[1..PHIL_COUNT] of string = ('Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell');
|
||||
type
|
||||
TFork = TCriticalSection;
|
||||
TPhilosopher = class;
|
||||
var
|
||||
Forks: array[1..PHIL_COUNT] of TFork;
|
||||
Philosophers: array[1..PHIL_COUNT] of TPhilosopher;
|
||||
type
|
||||
TPhilosopher = class(TThread)
|
||||
private
|
||||
FName: string;
|
||||
FLeftFork, FRightFork: TFork;
|
||||
FLefty: Boolean;
|
||||
procedure SetLefty(aValue: Boolean);
|
||||
procedure SwapForks;
|
||||
protected
|
||||
procedure Execute; override;
|
||||
public
|
||||
constructor Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
property Lefty: Boolean read FLefty write SetLefty;
|
||||
end;
|
||||
|
||||
procedure TPhilosopher.SetLefty(aValue: Boolean);
|
||||
begin
|
||||
if Lefty = aValue then
|
||||
exit;
|
||||
FLefty := aValue;
|
||||
SwapForks;
|
||||
end;
|
||||
|
||||
procedure TPhilosopher.SwapForks;
|
||||
var
|
||||
Fork: TFork;
|
||||
begin
|
||||
Fork := FLeftFork;
|
||||
FLeftFork := FRightFork;
|
||||
FRightFork := Fork;
|
||||
end;
|
||||
|
||||
procedure TPhilosopher.Execute;
|
||||
var
|
||||
LfSpan: Integer = LIFESPAN;
|
||||
begin
|
||||
while LfSpan > 0 do
|
||||
begin
|
||||
Dec(LfSpan);
|
||||
WriteLn(FName, ' sits down at the table');
|
||||
FLeftFork.Acquire;
|
||||
FRightFork.Acquire;
|
||||
WriteLn(FName, ' eating');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
FRightFork.Release;
|
||||
FLeftFork.Release;
|
||||
WriteLn(FName, ' is full and leaves the table');
|
||||
if LfSpan = 0 then
|
||||
continue;
|
||||
WriteLn(FName, ' thinking');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
WriteLn(FName, ' is hungry');
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TPhilosopher.Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
begin
|
||||
inherited Create(True);
|
||||
FName := aName;
|
||||
FLeftFork := Forks[aForkIdx1];
|
||||
FRightFork := Forks[aForkIdx2];
|
||||
end;
|
||||
|
||||
procedure DinnerBegin;
|
||||
var
|
||||
I: Integer;
|
||||
Phil: TPhilosopher;
|
||||
begin
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Forks[I] := TFork.Create;
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Philosophers[I] := TPhilosopher.Create(PHIL_NAMES[I], I, Succ(I mod PHIL_COUNT));
|
||||
Philosophers[Succ(Random(5))].Lefty := True;
|
||||
for Phil in Philosophers do
|
||||
Phil.Start;
|
||||
end;
|
||||
|
||||
procedure WaitForDinnerOver;
|
||||
var
|
||||
Phil: TPhilosopher;
|
||||
Fork: TFork;
|
||||
begin
|
||||
for Phil in Philosophers do
|
||||
begin
|
||||
Phil.WaitFor;
|
||||
Phil.Free;
|
||||
end;
|
||||
for Fork in Forks do
|
||||
Fork.Free;
|
||||
end;
|
||||
|
||||
begin
|
||||
Randomize;
|
||||
DinnerBegin;
|
||||
WaitForDinnerOver;
|
||||
end.
|
||||
101
Task/Dining-philosophers/Pascal/dining-philosophers-3.pas
Normal file
101
Task/Dining-philosophers/Pascal/dining-philosophers-3.pas
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
program dining_philosophers3;
|
||||
{$mode objfpc}{$H+}
|
||||
uses
|
||||
{$IFDEF UNIX}
|
||||
cthreads,
|
||||
{$ENDIF}
|
||||
Classes, SysUtils, SyncObjs;
|
||||
const
|
||||
PHIL_COUNT = 5;
|
||||
LIFESPAN = 7;
|
||||
DELAY_RANGE = 950;
|
||||
DELAY_LOW = 50;
|
||||
PHIL_NAMES: array[1..PHIL_COUNT] of string = ('Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell');
|
||||
type
|
||||
TFork = TCriticalSection;
|
||||
TPhilosopher = class;
|
||||
var
|
||||
Forks: array[1..PHIL_COUNT] of TFork;
|
||||
Philosophers: array[1..PHIL_COUNT] of TPhilosopher;
|
||||
type
|
||||
TPhilosopher = class(TThread)
|
||||
private
|
||||
FName: string;
|
||||
FLeftFork, FRightFork: TFork;
|
||||
protected
|
||||
procedure Execute; override;
|
||||
public
|
||||
constructor Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
end;
|
||||
|
||||
procedure TPhilosopher.Execute;
|
||||
var
|
||||
LfSpan: Integer = LIFESPAN;
|
||||
begin
|
||||
while LfSpan > 0 do
|
||||
begin
|
||||
Dec(LfSpan);
|
||||
WriteLn(FName, ' sits down at the table');
|
||||
repeat
|
||||
FLeftFork.Acquire;
|
||||
if not FRightFork.TryEnter then
|
||||
begin
|
||||
FLeftFork.Release;
|
||||
Sleep(Random(DELAY_RANGE));
|
||||
continue;
|
||||
end;
|
||||
break;
|
||||
until False;
|
||||
WriteLn(FName, ' eating');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
FRightFork.Release;
|
||||
FLeftFork.Release;
|
||||
WriteLn(FName, ' is full and leaves the table');
|
||||
if LfSpan = 0 then
|
||||
continue;
|
||||
WriteLn(FName, ' thinking');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
WriteLn(FName, ' is hungry');
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TPhilosopher.Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
begin
|
||||
inherited Create(True);
|
||||
FName := aName;
|
||||
FLeftFork := Forks[aForkIdx1];
|
||||
FRightFork := Forks[aForkIdx2];
|
||||
end;
|
||||
|
||||
procedure DinnerBegin;
|
||||
var
|
||||
I: Integer;
|
||||
Phil: TPhilosopher;
|
||||
begin
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Forks[I] := TFork.Create;
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Philosophers[I] := TPhilosopher.Create(PHIL_NAMES[I], I, Succ(I mod PHIL_COUNT));
|
||||
for Phil in Philosophers do
|
||||
Phil.Start;
|
||||
end;
|
||||
|
||||
procedure WaitForDinnerOver;
|
||||
var
|
||||
Phil: TPhilosopher;
|
||||
Fork: TFork;
|
||||
begin
|
||||
for Phil in Philosophers do
|
||||
begin
|
||||
Phil.WaitFor;
|
||||
Phil.Free;
|
||||
end;
|
||||
for Fork in Forks do
|
||||
Fork.Free;
|
||||
end;
|
||||
|
||||
begin
|
||||
Randomize;
|
||||
DinnerBegin;
|
||||
WaitForDinnerOver;
|
||||
end.
|
||||
114
Task/Dining-philosophers/Pascal/dining-philosophers-4.pas
Normal file
114
Task/Dining-philosophers/Pascal/dining-philosophers-4.pas
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
program dining_philosophers4;
|
||||
{$mode objfpc}{$H+}
|
||||
uses
|
||||
{$IFDEF UNIX}
|
||||
cthreads,
|
||||
{$ENDIF}
|
||||
Classes, SysUtils, SyncObjs;
|
||||
const
|
||||
PHIL_COUNT = 5;
|
||||
LIFESPAN = 7;
|
||||
DELAY_RANGE = 950;
|
||||
DELAY_LOW = 50;
|
||||
PHIL_NAMES: array[1..PHIL_COUNT] of string = ('Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell');
|
||||
type
|
||||
TFork = TCriticalSection;
|
||||
TPhilosopher = class;
|
||||
var
|
||||
Forks: array[1..PHIL_COUNT] of TFork;
|
||||
Philosophers: array[1..PHIL_COUNT] of TPhilosopher;
|
||||
StilDining: Integer = 0;
|
||||
procedure WaitForPlaceFree;
|
||||
begin
|
||||
repeat
|
||||
if InterlockedIncrement(StilDining) > Pred(PHIL_COUNT) then
|
||||
begin
|
||||
InterlockedDecrement(StilDining);
|
||||
Sleep(Random(DELAY_LOW));
|
||||
continue;
|
||||
end;
|
||||
exit;
|
||||
until False;
|
||||
end;
|
||||
|
||||
procedure FreePlace;
|
||||
begin
|
||||
InterLockedDecrement(StilDining);
|
||||
end;
|
||||
|
||||
type
|
||||
TPhilosopher = class(TThread)
|
||||
private
|
||||
FName: string;
|
||||
FLeftFork, FRightFork: TFork;
|
||||
protected
|
||||
procedure Execute; override;
|
||||
public
|
||||
constructor Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
end;
|
||||
|
||||
procedure TPhilosopher.Execute;
|
||||
var
|
||||
LfSpan: Integer = LIFESPAN;
|
||||
begin
|
||||
while LfSpan > 0 do
|
||||
begin
|
||||
Dec(LfSpan);
|
||||
WaitForPlaceFree;
|
||||
WriteLn(FName, ' sits down at the table');
|
||||
FLeftFork.Acquire;
|
||||
FRightFork.Acquire;
|
||||
WriteLn(FName, ' eating');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
FRightFork.Release;
|
||||
FLeftFork.Release;
|
||||
FreePlace;
|
||||
WriteLn(FName, ' is full and leaves the table');
|
||||
if LfSpan = 0 then
|
||||
continue;
|
||||
WriteLn(FName, ' thinking');
|
||||
Sleep(Random(DELAY_RANGE) + DELAY_LOW);
|
||||
WriteLn(FName, ' is hungry');
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TPhilosopher.Create(const aName: string; aForkIdx1, aForkIdx2: Integer);
|
||||
begin
|
||||
inherited Create(True);
|
||||
FName := aName;
|
||||
FLeftFork := Forks[aForkIdx1];
|
||||
FRightFork := Forks[aForkIdx2];
|
||||
end;
|
||||
|
||||
procedure DinnerBegin;
|
||||
var
|
||||
I: Integer;
|
||||
Phil: TPhilosopher;
|
||||
begin
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Forks[I] := TFork.Create;
|
||||
for I := 1 to PHIL_COUNT do
|
||||
Philosophers[I] := TPhilosopher.Create(PHIL_NAMES[I], I, Succ(I mod PHIL_COUNT));
|
||||
for Phil in Philosophers do
|
||||
Phil.Start;
|
||||
end;
|
||||
|
||||
procedure WaitForDinnerOver;
|
||||
var
|
||||
Phil: TPhilosopher;
|
||||
Fork: TFork;
|
||||
begin
|
||||
for Phil in Philosophers do
|
||||
begin
|
||||
Phil.WaitFor;
|
||||
Phil.Free;
|
||||
end;
|
||||
for Fork in Forks do
|
||||
Fork.Free;
|
||||
end;
|
||||
|
||||
begin
|
||||
Randomize;
|
||||
DinnerBegin;
|
||||
WaitForDinnerOver;
|
||||
end.
|
||||
50
Task/Dining-philosophers/Perl/dining-philosophers-1.pl
Normal file
50
Task/Dining-philosophers/Perl/dining-philosophers-1.pl
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use threads;
|
||||
use threads::shared;
|
||||
my @names = qw(Aristotle Kant Spinoza Marx Russell);
|
||||
|
||||
my @forks = ('On Table') x @names;
|
||||
share $forks[$_] for 0 .. $#forks;
|
||||
|
||||
sub pick_up_forks {
|
||||
my $philosopher = shift;
|
||||
my ($first, $second) = ($philosopher, $philosopher-1);
|
||||
($first, $second) = ($second, $first) if $philosopher % 2;
|
||||
for my $fork ( @forks[ $first, $second ] ) {
|
||||
lock $fork;
|
||||
cond_wait($fork) while $fork ne 'On Table';
|
||||
$fork = 'In Hand';
|
||||
}
|
||||
}
|
||||
|
||||
sub drop_forks {
|
||||
my $philosopher = shift;
|
||||
for my $fork ( @forks[$philosopher, $philosopher-1] ) {
|
||||
lock $fork;
|
||||
die unless $fork eq 'In Hand';
|
||||
$fork = 'On Table';
|
||||
cond_signal($fork);
|
||||
}
|
||||
}
|
||||
|
||||
sub philosopher {
|
||||
my $philosopher = shift;
|
||||
my $name = $names[$philosopher];
|
||||
for my $meal ( 1..5 ) {
|
||||
print $name, " is pondering\n";
|
||||
sleep 1 + rand 8;
|
||||
print $name, " is hungry\n";
|
||||
pick_up_forks( $philosopher );
|
||||
print $name, " is eating\n";
|
||||
sleep 1 + rand 8;
|
||||
drop_forks( $philosopher );
|
||||
}
|
||||
print $name, " is done\n";
|
||||
}
|
||||
|
||||
my @t = map { threads->new(\&philosopher, $_) } 0 .. $#names;
|
||||
for my $thread ( @t ) {
|
||||
$thread->join;
|
||||
}
|
||||
|
||||
print "Done\n";
|
||||
__END__
|
||||
40
Task/Dining-philosophers/Perl/dining-philosophers-2.pl
Normal file
40
Task/Dining-philosophers/Perl/dining-philosophers-2.pl
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/perl
|
||||
use common::sense;
|
||||
use Coro;
|
||||
use AnyEvent;
|
||||
use Coro::AnyEvent;
|
||||
use EV;
|
||||
|
||||
my @philosophers = qw(Aristotle Kant Spinoza Marx Russell);
|
||||
my @forks = (1..@philosophers);
|
||||
my @fork_sem;
|
||||
|
||||
$fork_sem[$_] = Coro::Semaphore->new for (0..$#philosophers);
|
||||
|
||||
|
||||
for(my $i = $#philosophers; $i >= 0; $i--){
|
||||
say $philosophers[$i] . " has fork #" . $forks[$i] . " and fork #" . $forks[$i-1];
|
||||
async {
|
||||
my ($name, ,$no, $forks_got) = (@_);
|
||||
|
||||
$Coro::current->{desc} = $name;
|
||||
Coro::AnyEvent::sleep(rand 4);
|
||||
|
||||
while(1){
|
||||
say $name . " is hungry.";
|
||||
$$forks_got[$no]->down();
|
||||
Coro::AnyEvent::sleep(rand 1); #Let's make deadlock!
|
||||
$$forks_got[$no-1]->down();
|
||||
say $name . " is eating.";
|
||||
Coro::AnyEvent::sleep(1 + rand 8);
|
||||
|
||||
$$forks_got[$no]->up();
|
||||
$$forks_got[$no-1]->up();
|
||||
|
||||
say $name . " is thinking.";
|
||||
Coro::AnyEvent::sleep(1 + rand 8);
|
||||
}
|
||||
}($philosophers[$i], $i, \@fork_sem);
|
||||
}
|
||||
|
||||
EV::loop;
|
||||
52
Task/Dining-philosophers/Phix/dining-philosophers.phix
Normal file
52
Task/Dining-philosophers/Phix/dining-philosophers.phix
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
(notonline)-->
|
||||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- threads</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">fork1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_cs</span><span style="color: #0000FF;">(),</span>
|
||||
<span style="color: #000000;">fork2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_cs</span><span style="color: #0000FF;">(),</span>
|
||||
<span style="color: #000000;">fork3</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_cs</span><span style="color: #0000FF;">(),</span>
|
||||
<span style="color: #000000;">fork4</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_cs</span><span style="color: #0000FF;">(),</span>
|
||||
<span style="color: #000000;">fork5</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_cs</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">terminate</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- control flag</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">person</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">name</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">left_fork</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">right_fork</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- (except Russell, who gets left and right the other way round)</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">terminate</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #7060A8;">enter_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">left_fork</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">enter_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">right_fork</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" grabs forks.\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000080;font-style:italic;">-- if terminate then exit end if</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" is eating.\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- sleep(1)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" puts forks down and leaves the dinning room.\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">leave_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">left_fork</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">leave_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">right_fork</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000080;font-style:italic;">-- if terminate then exit end if</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" is thinking.\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- sleep(1)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" becomes hungry.\n"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">r_person</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"person"</span><span style="color: #0000FF;">)</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">threads</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r_person</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"Aristotle"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork2</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #000000;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r_person</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"Kant"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork3</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #000000;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r_person</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"Spinoza"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork4</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #000000;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r_person</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"Marx"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork5</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #000080;font-style:italic;">-- create_thread(r_person,{"Russell",fork5,fork1})} -- this will deadlock!</span>
|
||||
<span style="color: #000000;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r_person</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"Russell"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fork5</span><span style="color: #0000FF;">})}</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">ESC</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">#1B</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">get_key</span><span style="color: #0000FF;">(),{</span><span style="color: #000000;">ESC</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'q'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'Q'</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #000000;">terminate</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">wait_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">threads</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (not strictly necessary)</span>
|
||||
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fork1</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- ""</span>
|
||||
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fork2</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fork3</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fork4</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fork5</span><span style="color: #0000FF;">)</span>
|
||||
<!--
|
||||
36
Task/Dining-philosophers/PicoLisp/dining-philosophers.l
Normal file
36
Task/Dining-philosophers/PicoLisp/dining-philosophers.l
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
(de dining (Name State)
|
||||
(loop
|
||||
(prinl Name ": " State)
|
||||
(state 'State # Dispatch according to state
|
||||
(thinking 'hungry) # If thinking, get hungry
|
||||
(hungry # If hungry, grab random fork
|
||||
(if (rand T)
|
||||
(and (acquire leftFork) 'leftFork)
|
||||
(and (acquire rightFork) 'rightFork) ) )
|
||||
(hungry 'hungry # Failed, stay hungry for a while
|
||||
(wait (rand 1000 3000)) )
|
||||
(leftFork # If holding left fork, try right one
|
||||
(and (acquire rightFork) 'eating)
|
||||
(wait 2000) ) # then eat for 2 seconds
|
||||
(rightFork # If holding right fork, try left one
|
||||
(and (acquire leftFork) 'eating)
|
||||
(wait 2000) ) # then eat for 2 seconds
|
||||
((leftFork rightFork) 'hungry # Otherwise, go back to hungry,
|
||||
(release (val State)) # release left or right fork
|
||||
(wait (rand 1000 3000)) ) # and stay hungry
|
||||
(eating 'thinking # After eating, resume thinking
|
||||
(release leftFork)
|
||||
(release rightFork)
|
||||
(wait 6000) ) ) ) ) # for 6 seconds
|
||||
|
||||
(setq *Philosophers
|
||||
(maplist
|
||||
'((Phils Forks)
|
||||
(let (leftFork (tmp (car Forks)) rightFork (tmp (cadr Forks)))
|
||||
(or
|
||||
(fork) # Parent: Collect child process IDs
|
||||
(dining (car Phils) 'hungry) ) ) ) # Initially hungry
|
||||
'("Aristotle" "Kant" "Spinoza" "Marx" "Russell")
|
||||
'("ForkA" "ForkB" "ForkC" "ForkD" "ForkE" .) ) )
|
||||
|
||||
(push '*Bye '(mapc kill *Philosophers)) # Terminate all upon exit
|
||||
94
Task/Dining-philosophers/Pike/dining-philosophers.pike
Normal file
94
Task/Dining-philosophers/Pike/dining-philosophers.pike
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
class Philosopher
|
||||
{
|
||||
string name;
|
||||
object left;
|
||||
object right;
|
||||
|
||||
void create(string _name, object _left, object _right)
|
||||
{
|
||||
name = _name;
|
||||
left = _left;
|
||||
right = _right;
|
||||
}
|
||||
|
||||
void take_forks()
|
||||
{
|
||||
if (left->take(this) && right->take(this))
|
||||
{
|
||||
write("%s is EATING\n", name);
|
||||
call_out(drop_forks, random(30));
|
||||
}
|
||||
else
|
||||
{
|
||||
write("%s is WAITING\n", name);
|
||||
if (random(10) >= 8)
|
||||
drop_forks();
|
||||
call_out(take_forks, random(10));
|
||||
}
|
||||
}
|
||||
|
||||
void drop_forks()
|
||||
{
|
||||
left->drop(this);
|
||||
right->drop(this);
|
||||
write("%s is THINKING\n", name);
|
||||
call_out(take_forks, random(30));
|
||||
}
|
||||
}
|
||||
|
||||
class Fork
|
||||
{
|
||||
int number;
|
||||
Philosopher user;
|
||||
|
||||
void create(int _number)
|
||||
{
|
||||
number = _number;
|
||||
}
|
||||
|
||||
int take(object new_user)
|
||||
{
|
||||
if (!user)
|
||||
{
|
||||
write("%s takes fork %d\n", new_user->name, number);
|
||||
user = new_user;
|
||||
return 1;
|
||||
}
|
||||
else if (new_user == user)
|
||||
{
|
||||
write("%s has fork %d\n", new_user->name, number);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
write("%s tries to take fork %d from %s\n", new_user->name, number, user->name);
|
||||
}
|
||||
|
||||
void drop(object old_user)
|
||||
{
|
||||
if (old_user == user)
|
||||
{
|
||||
write("%s drops fork %d\n", old_user->name, number);
|
||||
user = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, array argv)
|
||||
{
|
||||
|
||||
array forks = ({ Fork(1), Fork(2), Fork(3), Fork(4), Fork(5) });
|
||||
array philosophers = ({
|
||||
Philosopher("einstein", forks[0], forks[1]),
|
||||
Philosopher("plato", forks[1], forks[2]),
|
||||
Philosopher("sokrates", forks[2], forks[3]),
|
||||
Philosopher("chomsky", forks[3], forks[4]),
|
||||
Philosopher("archimedes", forks[4], forks[0]),
|
||||
});
|
||||
|
||||
call_out(philosophers[0]->take_forks, random(5));
|
||||
call_out(philosophers[1]->take_forks, random(5));
|
||||
call_out(philosophers[2]->take_forks, random(5));
|
||||
call_out(philosophers[3]->take_forks, random(5));
|
||||
call_out(philosophers[4]->take_forks, random(5));
|
||||
return -1;
|
||||
}
|
||||
449
Task/Dining-philosophers/Prolog/dining-philosophers.pro
Normal file
449
Task/Dining-philosophers/Prolog/dining-philosophers.pro
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
dining_philosophers :-
|
||||
new(D, window('Dining philosophers')),
|
||||
new(S, window('Dining philosophers : statistics')),
|
||||
send(D, size, new(_, size(800,800))),
|
||||
|
||||
new(E, ellipse(400,400)),
|
||||
send(E, center, point(400,400)),
|
||||
send(D, display, E),
|
||||
|
||||
new(F1, fork(0)),
|
||||
new(F2, fork(1)),
|
||||
new(F3, fork(2)),
|
||||
new(F4, fork(3)),
|
||||
new(F5, fork(4)),
|
||||
|
||||
send_list(D, display, [F1,F2,F3,F4,F5]),
|
||||
|
||||
new(Waiter, waiter(F1, F2, F3, F4, F5)),
|
||||
|
||||
create_plate(P1, 0),
|
||||
create_plate(P2, 1),
|
||||
create_plate(P3, 2),
|
||||
create_plate(P4, 3),
|
||||
create_plate(P5, 4),
|
||||
|
||||
create_point(0, Pt1),
|
||||
create_point(1, Pt2),
|
||||
create_point(2, Pt3),
|
||||
create_point(3, Pt4),
|
||||
create_point(4, Pt5),
|
||||
|
||||
|
||||
new(Ph1, philosopher('Aristotle', Waiter, P1, D, S, 0, Pt1, left)),
|
||||
new(Ph2, philosopher('Kant', Waiter, P2, D, S, 1, Pt2, left)),
|
||||
new(Ph3, philosopher('Spinoza', Waiter, P3, D, S, 2, Pt3, right)),
|
||||
new(Ph4, philosopher('Marx', Waiter, P4, D, S, 3, Pt4, right)),
|
||||
new(Ph5, philosopher('Russell', Waiter, P5, D, S, 4, Pt5, left)),
|
||||
|
||||
send(Waiter, init_phi, Ph1, Ph2, Ph3, Ph4, Ph5),
|
||||
|
||||
send_list([Ph1, Ph2, Ph3, Ph4, Ph5], start),
|
||||
|
||||
send(D, done_message, and(message(Waiter, free),
|
||||
message(Ph1, free),
|
||||
message(Ph2, free),
|
||||
message(Ph3, free),
|
||||
message(Ph4, free),
|
||||
message(Ph5, free),
|
||||
message(S, open),
|
||||
message(D, destroy))),
|
||||
|
||||
send(D, open).
|
||||
|
||||
|
||||
create_plate(P, N) :-
|
||||
new(P, ellipse(80,80)),
|
||||
X is 400 + 140 * cos(N * pi / 2.5),
|
||||
Y is 400 + 140 * sin(N * pi / 2.5),
|
||||
send(P, center, point(X, Y)).
|
||||
|
||||
create_point(N, point(X, Y)) :-
|
||||
X is 400 + 220 * cos(N * pi / 2.5),
|
||||
Y is 400 + 220 * sin(N * pi / 2.5) - 20.
|
||||
|
||||
|
||||
:- pce_begin_class(waiter , object, "gives the forks to the philosophers").
|
||||
variable(f1, fork, both, "free or used").
|
||||
variable(f2, fork, both, "free or used").
|
||||
variable(f3, fork, both, "free or used").
|
||||
variable(f4, fork, both, "free or used").
|
||||
variable(f5, fork, both, "free or used").
|
||||
variable(phi1, philosopher, both, "philosopher").
|
||||
variable(phi2, philosopher, both, "philosopher").
|
||||
variable(phi3, philosopher, both, "philosopher").
|
||||
variable(phi4, philosopher, both, "philosopher").
|
||||
variable(phi5, philosopher, both, "philosopher").
|
||||
|
||||
initialise(P, F1, F2, F3, F4, F5) :->
|
||||
send(P, slot, f1, F1),
|
||||
send(P, slot, f2, F2),
|
||||
send(P, slot, f3, F3),
|
||||
send(P, slot, f4, F4),
|
||||
send(P, slot, f5, F5).
|
||||
|
||||
init_phi(P, Phi1,Phi2, Phi3, Phi4, Phi5) :->
|
||||
send(P, slot, phi1, Phi1),
|
||||
send(P, slot, phi2, Phi2),
|
||||
send(P, slot, phi3, Phi3),
|
||||
send(P, slot, phi4, Phi4),
|
||||
send(P, slot, phi5, Phi5).
|
||||
|
||||
|
||||
want_forks(P, Phi) :->
|
||||
( get(P, slot, phi1, Phi) ,!, check_forks(P, Phi, f5, f1);
|
||||
get(P, slot, phi2, Phi),!, check_forks(P, Phi, f1, f2);
|
||||
get(P, slot, phi3, Phi),!, check_forks(P, Phi, f2, f3);
|
||||
get(P, slot, phi4, Phi),!, check_forks(P, Phi, f3, f4);
|
||||
get(P, slot, phi5, Phi),!, check_forks(P, Phi, f4, f5)).
|
||||
|
||||
|
||||
|
||||
|
||||
give_back_forks(P, Phi) :->
|
||||
( get(P, slot, phi1, Phi) ,!, release_forks(P, phi1);
|
||||
get(P, slot, phi2, Phi),!, release_forks(P, phi2);
|
||||
get(P, slot, phi3, Phi),!, release_forks(P, phi3);
|
||||
get(P, slot, phi4, Phi),!, release_forks(P, phi4);
|
||||
get(P, slot, phi5, Phi),!, release_forks(P, phi5)),
|
||||
|
||||
get(P, slot, phi1, Phi1),
|
||||
check_forks(P, Phi1, f5, f1),
|
||||
get(P, slot, phi2, Phi2),
|
||||
check_forks(P, Phi2, f1, f2),
|
||||
get(P, slot, phi3, Phi3),
|
||||
check_forks(P, Phi3, f2, f3),
|
||||
get(P, slot, phi4, Phi4),
|
||||
check_forks(P, Phi4, f3, f4),
|
||||
get(P, slot, phi5, Phi5),
|
||||
check_forks(P, Phi5, f4, f5).
|
||||
|
||||
release_forks(P, phi1) :-
|
||||
get(P, slot, f5, F5),
|
||||
send(F5, free),
|
||||
get(P, slot, f1, F1),
|
||||
send(F1, free).
|
||||
|
||||
release_forks(P, phi2) :-
|
||||
get(P, slot, f1, F1),
|
||||
send(F1, free),
|
||||
get(P, slot, f2, F2),
|
||||
send(F2, free).
|
||||
|
||||
release_forks(P, phi3) :-
|
||||
get(P, slot, f2, F2),
|
||||
send(F2, free),
|
||||
get(P, slot, f3, F3),
|
||||
send(F3, free).
|
||||
|
||||
release_forks(P, phi4) :-
|
||||
get(P, slot, f3, F3),
|
||||
send(F3, free),
|
||||
get(P, slot, f4, F4),
|
||||
send(F4, free).
|
||||
|
||||
release_forks(P, phi5) :-
|
||||
get(P, slot, f4, F4),
|
||||
send(F4, free),
|
||||
get(P, slot, f5, F5),
|
||||
send(F5, free).
|
||||
|
||||
check_forks(P, Phi, F1, F2) :-
|
||||
get(P, slot, F1, FF1),
|
||||
get(P, slot, F2, FF2),
|
||||
( (get(Phi, slot, status, waiting),
|
||||
get(FF1, slot, status, free),
|
||||
get(FF2, slot, status, free))
|
||||
->
|
||||
send(Phi, receive_forks),
|
||||
send(FF1, used, right),
|
||||
send(FF2, used, left)
|
||||
;
|
||||
true).
|
||||
|
||||
:- pce_end_class.
|
||||
|
||||
|
||||
:- pce_begin_class(philosopher , object, "eat, think or wait !").
|
||||
variable(name, string, both).
|
||||
variable(window, object, both).
|
||||
variable(status, object, both, "eating/thinking/waiting").
|
||||
variable(waiter, object, both).
|
||||
variable(plate, object, both).
|
||||
variable(mytimer, timer, both).
|
||||
variable(pos, point, both).
|
||||
variable(side, object, both).
|
||||
variable(old_text, object, both).
|
||||
variable(window_stat, object, both).
|
||||
variable(line_stat, number, both).
|
||||
variable(stat_wait, my_stat, both).
|
||||
variable(stat_eat, my_stat, both).
|
||||
variable(stat_think, my_stat, both).
|
||||
|
||||
% méthode appelée lors de la destruction de l'objet
|
||||
% On arrête d'abord le timer pour poursuivre ensuite
|
||||
% sans problème (appel par le timer de ressources libérées)
|
||||
unlink(P) :->
|
||||
send(P?mytimer, stop),
|
||||
|
||||
get(P, status, Sta),
|
||||
stop_timer(P, Sta),
|
||||
get(P, slot, window_stat, WS),
|
||||
get(P, slot, line_stat, LS),
|
||||
get(LS, value, VLS),
|
||||
get(P, slot, name, Name),
|
||||
get(Name, value, V),
|
||||
sformat(A, 'Statistics of philosopher : ~w', [V]),
|
||||
new(Text, text(A)),
|
||||
send(Text, font, font(times, bold, 16)),
|
||||
Y is VLS * 30,
|
||||
send(WS, display, Text, point(30, Y)),
|
||||
|
||||
VLS1 is VLS+1,
|
||||
get(P, slot, stat_think, ST),
|
||||
send(ST, statistics, WS, VLS1),
|
||||
|
||||
VLS2 is VLS+2,
|
||||
get(P, slot, stat_eat, SE),
|
||||
send(SE, statistics, WS, VLS2),
|
||||
|
||||
VLS3 is VLS+3,
|
||||
get(P, slot, stat_wait, SW),
|
||||
send(SW, statistics, WS, VLS3),
|
||||
|
||||
send(P, send_super, unlink).
|
||||
|
||||
initialise(P, Name, Waiter, Plate, Window, Window_stat, Line_stat, Point, Side) :->
|
||||
% gtrace,
|
||||
send(P, slot, name, Name),
|
||||
send(P, slot, window, Window),
|
||||
send(P, slot, window_stat, Window_stat),
|
||||
Line is Line_stat * 5,
|
||||
send(P, slot, line_stat, Line),
|
||||
send(P, slot, waiter,Waiter),
|
||||
send(P, slot, plate,Plate),
|
||||
send(P, slot, status, thinking),
|
||||
send(P, slot, pos, Point),
|
||||
send(P, slot, side, Side),
|
||||
send(Window, display, Plate),
|
||||
send(P, slot, old_text, new(_, text(' '))),
|
||||
send(P, display_status),
|
||||
send(P, slot, stat_wait, new(_, my_stat('Waiting'))),
|
||||
send(P, slot, stat_eat, new(_, my_stat('Eating'))),
|
||||
send(P, slot, stat_think, new(_, my_stat('Thinking'))).
|
||||
|
||||
|
||||
stop_timer(P, eating) :-
|
||||
get(P, slot, stat_eat, SE),
|
||||
send(SE, stop).
|
||||
|
||||
stop_timer(P, waiting) :-
|
||||
get(P, slot, stat_wait, SW),
|
||||
send(SW, stop).
|
||||
|
||||
stop_timer(P, thinking) :-
|
||||
get(P, slot, stat_think, ST),
|
||||
send(ST, stop).
|
||||
|
||||
|
||||
% internal message send by the timer
|
||||
my_message(P) :->
|
||||
% gtrace,
|
||||
get(P, slot, status, Status),
|
||||
next_status(P, Status).
|
||||
|
||||
% philosopher eating ==> thinking
|
||||
next_status(P, eating) :-
|
||||
get(P, slot, waiter, Waiter),
|
||||
get(P, slot, stat_eat, SE),
|
||||
send(SE, stop),
|
||||
get(P, slot, stat_think, ST),
|
||||
send(ST, start),
|
||||
send(Waiter, give_back_forks, P),
|
||||
send(P, slot, status, thinking),
|
||||
send(P, display_status),
|
||||
get(P, plate, Plate),
|
||||
send(Plate, fill_pattern, colour(white)),
|
||||
I is random(20)+ 10,
|
||||
get(P, slot, mytimer, Timer),
|
||||
send(Timer, interval, I),
|
||||
send(Timer, start, once).
|
||||
|
||||
next_status(P, thinking) :-
|
||||
get(P, slot, waiter, Waiter),
|
||||
send(P, slot, status, waiting),
|
||||
send(P, display_status),
|
||||
get(P, slot, stat_think, ST),
|
||||
send(ST, stop),
|
||||
get(P, slot, stat_wait, SW),
|
||||
send(SW, start),
|
||||
send(Waiter, want_forks, P).
|
||||
|
||||
% send by the waiter
|
||||
% philosopher can eat !
|
||||
receive_forks(P) :->
|
||||
get(P, slot, stat_wait, SW),
|
||||
send(SW, stop),
|
||||
get(P, slot, stat_eat, SE),
|
||||
send(SE, start),
|
||||
send(P, slot, status, eating),
|
||||
send(P, display_status),
|
||||
get(P, plate, Plate),
|
||||
send(Plate, fill_pattern, colour(black)),
|
||||
I is random(20)+ 5,
|
||||
get(P, slot, mytimer, Timer),
|
||||
send(Timer, interval, I),
|
||||
send(Timer, start, once).
|
||||
|
||||
display_status(P) :->
|
||||
get(P, old_text, OT),
|
||||
free(OT),
|
||||
get(P, name, Name),
|
||||
get(Name, value, V),
|
||||
get(P, status, Status),
|
||||
choose_color(Status, Colour),
|
||||
sformat(A, '~w ~w', [V, Status]),
|
||||
get(P, window, W),
|
||||
get(P, pos, point(X, Y)),
|
||||
new(Text, text(A)),
|
||||
send(Text, font, font(times, bold, 16)),
|
||||
send(Text, colour, Colour),
|
||||
get(Text, string, Str),
|
||||
get(font(times, bold, 16), width(Str), M),
|
||||
(get(P, side, right) -> X1 is X - M; X1 = X),
|
||||
send(W, display, Text, point(X1, Y)),
|
||||
send(P, old_text, Text).
|
||||
|
||||
|
||||
start(P) :->
|
||||
I is random(10)+ 2,
|
||||
get(P, slot, stat_think, ST),
|
||||
send(ST, start),
|
||||
send(P, mytimer, new(_, timer(I,message(P, my_message)))),
|
||||
send(P?mytimer, start, once).
|
||||
|
||||
|
||||
choose_color(eating, colour(blue)).
|
||||
choose_color(thinking, colour(green)).
|
||||
choose_color(waiting, colour(red)).
|
||||
|
||||
:- pce_end_class.
|
||||
|
||||
|
||||
|
||||
:- pce_begin_class(disk, ellipse, "disk with color ").
|
||||
|
||||
initialise(P, C, R, Col) :->
|
||||
send(P, send_super, initialise, R, R),
|
||||
send(P, center, C),
|
||||
send(P, pen, 0),
|
||||
send(P, fill_pattern, Col).
|
||||
|
||||
change_color(P, Col) :->
|
||||
send(P, fill_pattern, Col).
|
||||
|
||||
:- pce_end_class.
|
||||
|
||||
:- pce_begin_class(my_stat , object, "statistics").
|
||||
variable(name, string, both).
|
||||
variable(nb, number, both).
|
||||
variable(duration, real, both).
|
||||
variable(start, real, both).
|
||||
|
||||
initialise(P, Name) :->
|
||||
send(P, name, Name),
|
||||
send(P, nb, 0),
|
||||
send(P, duration, 0.0).
|
||||
|
||||
start(P) :->
|
||||
get_time(T),
|
||||
send(P, slot, start, T).
|
||||
|
||||
stop(P) :->
|
||||
get_time(Fin),
|
||||
|
||||
get(P, slot, nb, N),
|
||||
send(N, plus,1),
|
||||
send(P, slot, nb, N),
|
||||
|
||||
get(P, slot, duration, D),
|
||||
get(P, slot, start, Deb),
|
||||
|
||||
get(D, value, VD),
|
||||
get(Deb, value, VDeb),
|
||||
X is VD + Fin - VDeb,
|
||||
|
||||
send(P, slot, duration, X).
|
||||
|
||||
statistics(P, W, L) :->
|
||||
get(P, nb, N),
|
||||
get(N, value, VN),
|
||||
get(P, duration, D),
|
||||
get(D, value, VD),
|
||||
get(P, name, Name),
|
||||
get(Name, value, V),
|
||||
sformat(A, '~w~tnb :~13| ~t~w~17| duration : ~t~1f~35|', [V, VN, VD]),
|
||||
new(Text, text(A)),
|
||||
send(Text, font, font(screen, roman, 14)),
|
||||
Y is L * 30,
|
||||
send(W, display, Text, point(40, Y)).
|
||||
|
||||
:-pce_end_class.
|
||||
|
||||
% forks changes of place
|
||||
:- pce_begin_class(fork, line, "to help philosopphers to eat").
|
||||
variable(value, number, both, "0 => 4").
|
||||
variable(side, object, both), "left / right".
|
||||
variable(status, object, both, "free / used").
|
||||
|
||||
initialise(P, Val) :->
|
||||
send_super(P, initialise),
|
||||
send(P, slot, value, Val),
|
||||
send(P, slot, status, free),
|
||||
compute(Val, free, _, PS, PE),
|
||||
send(P, start, PS),
|
||||
send(P, end, PE).
|
||||
|
||||
free(P) :->
|
||||
send(P, status, free),
|
||||
send(P, position).
|
||||
|
||||
|
||||
used(P, Side) :->
|
||||
send(P, status, used),
|
||||
send(P, side, Side),
|
||||
send(P, position).
|
||||
|
||||
position(P) :->
|
||||
get(P, value, V),
|
||||
get(V, value, N),
|
||||
get(P, status, St),
|
||||
get(P, side, Side),
|
||||
compute(N, St, Side, PS, PE),
|
||||
send(P, start, PS),
|
||||
send(P, end, PE).
|
||||
|
||||
|
||||
compute(N, free, _Side, point(XS,YS), point(XE,YE)) :-
|
||||
A is N * pi / 2.5 + pi / 5,
|
||||
XS is 400 + 100 * cos(A),
|
||||
YS is 400 + 100 * sin(A),
|
||||
XE is 400 + 180 * cos(A),
|
||||
YE is 400 + 180 * sin(A).
|
||||
|
||||
|
||||
compute(N, used, left, point(XS,YS), point(XE,YE)) :-
|
||||
A is N * pi / 2.5 + pi / 5 - 2 * pi / 15,
|
||||
XS is 400 + 100 * cos(A),
|
||||
YS is 400 + 100 * sin(A),
|
||||
XE is 400 + 180 * cos(A),
|
||||
YE is 400 + 180 * sin(A).
|
||||
|
||||
compute(N, used, right, point(XS,YS), point(XE,YE)) :-
|
||||
A is N * pi / 2.5 + pi / 5 + 2 * pi / 15,
|
||||
XS is 400 + 100 * cos(A),
|
||||
YS is 400 + 100 * sin(A),
|
||||
XE is 400 + 180 * cos(A),
|
||||
YE is 400 + 180 * sin(A).
|
||||
|
||||
:- pce_end_class.
|
||||
117
Task/Dining-philosophers/PureBasic/dining-philosophers.basic
Normal file
117
Task/Dining-philosophers/PureBasic/dining-philosophers.basic
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
Macro Tell(Mutex, Message) ; Make a macro to easy send info back to main thread
|
||||
LockMutex(Mutex)
|
||||
LastElement(Queue())
|
||||
AddElement(Queue())
|
||||
Queue() = Message
|
||||
SignalSemaphore(Semaphore)
|
||||
UnlockMutex(Mutex)
|
||||
EndMacro
|
||||
|
||||
;Set up a data structure to pass needed info into the threads
|
||||
Structure Thread_Parameters
|
||||
Name.s
|
||||
fork1.i
|
||||
fork2.i
|
||||
EndStructure
|
||||
|
||||
; Declare function to be used
|
||||
Declare.i TryFork(n)
|
||||
Declare PutDownFork(n)
|
||||
Declare Invite(Namn.s, Fork1, Fork2)
|
||||
Declare _philosophers(*arg.Thread_Parameters)
|
||||
|
||||
Global Semaphore = CreateSemaphore()
|
||||
Global Mutex1 = CreateMutex() ; Eg. fork 1
|
||||
Global Mutex2 = CreateMutex() ; Eg. fork 2
|
||||
Global Mutex3 = CreateMutex() ; Eg. fork 3
|
||||
Global Mutex4 = CreateMutex() ; Eg. fork 4
|
||||
Global Mutex5 = CreateMutex() ; Eg. fork 5
|
||||
Global Mutex_main = CreateMutex() ; locking communication with the main thread which do all output.
|
||||
Global NewList Queue.s()
|
||||
|
||||
If OpenConsole()
|
||||
Invite("Aristotle",1,2) ; Get all Philosophers activated
|
||||
Invite("Kant", 2,3)
|
||||
Invite("Spinoza", 3,4)
|
||||
Invite("Marx", 4,5)
|
||||
Invite("Russell", 5,1)
|
||||
CompilerIf #PB_Compiler_OS=#PB_OS_Windows
|
||||
SetConsoleTitle_("Dining philosophers, by Jofur") ; Using a Windows-API here, so checking before
|
||||
CompilerEndIf
|
||||
; Wait and see if any Philosophers want to tell me anything
|
||||
Repeat
|
||||
WaitSemaphore(Semaphore)
|
||||
LockMutex(Mutex_main)
|
||||
ForEach Queue()
|
||||
PrintN( Queue() ) ; Print what the Philosopher(s) told me
|
||||
i-1
|
||||
Next Queue()
|
||||
ClearList(Queue())
|
||||
UnlockMutex(Mutex_main)
|
||||
ForEver
|
||||
EndIf
|
||||
|
||||
Procedure TryFork(n) ; Se is fork #n is free and if so pick it up
|
||||
Select n
|
||||
Case 1: ProcedureReturn TryLockMutex(Mutex1)
|
||||
Case 2: ProcedureReturn TryLockMutex(Mutex2)
|
||||
Case 3: ProcedureReturn TryLockMutex(Mutex3)
|
||||
Case 4: ProcedureReturn TryLockMutex(Mutex4)
|
||||
Default:ProcedureReturn TryLockMutex(Mutex5)
|
||||
EndSelect
|
||||
EndProcedure
|
||||
|
||||
Procedure PutDownFork(n) ; put down fork #n and free it to be used by neighbors.
|
||||
Select n
|
||||
Case 1: UnlockMutex(Mutex1)
|
||||
Case 2: UnlockMutex(Mutex2)
|
||||
Case 3: UnlockMutex(Mutex3)
|
||||
Case 4: UnlockMutex(Mutex4)
|
||||
Default:UnlockMutex(Mutex5)
|
||||
EndSelect
|
||||
EndProcedure
|
||||
|
||||
Procedure Invite(Namn.s, Fork1, Fork2)
|
||||
Protected *arg.Thread_Parameters ;create the structure containing the parameters
|
||||
Protected Thread
|
||||
*arg = AllocateMemory(SizeOf(Thread_Parameters))
|
||||
*arg\Name = Namn
|
||||
*arg\fork1 = Fork1
|
||||
*arg\fork2 = Fork2
|
||||
Thread=CreateThread(@_philosophers(), *arg) ;send the thread a pointer to our structure
|
||||
ProcedureReturn Thread
|
||||
EndProcedure
|
||||
|
||||
Procedure _philosophers(*arg.Thread_Parameters)
|
||||
Protected Iam.s=*arg\Name, j=*arg\fork1, k=*arg\fork2
|
||||
Protected f1, f2
|
||||
ClearStructure(*arg, Thread_Parameters)
|
||||
FreeMemory(*arg)
|
||||
;
|
||||
Repeat
|
||||
Tell(Mutex_main,Iam+": Going to the table")
|
||||
Repeat ;Trying to get my two forks
|
||||
f1=TryFork(j)
|
||||
If f1
|
||||
f2=TryFork(k)
|
||||
If Not f2 ; I got only one fork
|
||||
PutDownFork(j)
|
||||
f1=0
|
||||
EndIf
|
||||
EndIf
|
||||
If Not f2
|
||||
Delay(Random(100)) ; Take a short breath, then try the forks in the other order
|
||||
Swap j,k
|
||||
EndIf
|
||||
Until f1 And f2
|
||||
Tell(Mutex_main,Iam+": I have fork #"+Str(j)+" & #"+Str(k)+" and I'm eating now")
|
||||
Delay(Random(1500)+15)
|
||||
Tell(Mutex_main,Iam+": release fork #"+Str(j)+" & #"+Str(k)+"")
|
||||
Delay(Random(45)+15)
|
||||
PutDownFork(j)
|
||||
PutDownFork(k)
|
||||
f1=0:f2=0
|
||||
Tell(Mutex_main,Iam+": Thinking about the nature of the universe...")
|
||||
Delay(Random(2500)+25)
|
||||
ForEver
|
||||
EndProcedure
|
||||
67
Task/Dining-philosophers/Python/dining-philosophers.py
Normal file
67
Task/Dining-philosophers/Python/dining-philosophers.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import threading
|
||||
import random
|
||||
import time
|
||||
|
||||
# Dining philosophers, 5 Phillies with 5 forks. Must have two forks to eat.
|
||||
#
|
||||
# Deadlock is avoided by never waiting for a fork while holding a fork (locked)
|
||||
# Procedure is to do block while waiting to get first fork, and a nonblocking
|
||||
# acquire of second fork. If failed to get second fork, release first fork,
|
||||
# swap which fork is first and which is second and retry until getting both.
|
||||
#
|
||||
# See discussion page note about 'live lock'.
|
||||
|
||||
class Philosopher(threading.Thread):
|
||||
|
||||
running = True
|
||||
|
||||
def __init__(self, xname, forkOnLeft, forkOnRight):
|
||||
threading.Thread.__init__(self)
|
||||
self.name = xname
|
||||
self.forkOnLeft = forkOnLeft
|
||||
self.forkOnRight = forkOnRight
|
||||
|
||||
def run(self):
|
||||
while(self.running):
|
||||
# Philosopher is thinking (but really is sleeping).
|
||||
time.sleep( random.uniform(3,13))
|
||||
print '%s is hungry.' % self.name
|
||||
self.dine()
|
||||
|
||||
def dine(self):
|
||||
fork1, fork2 = self.forkOnLeft, self.forkOnRight
|
||||
|
||||
while self.running:
|
||||
fork1.acquire(True)
|
||||
locked = fork2.acquire(False)
|
||||
if locked: break
|
||||
fork1.release()
|
||||
print '%s swaps forks' % self.name
|
||||
fork1, fork2 = fork2, fork1
|
||||
else:
|
||||
return
|
||||
|
||||
self.dining()
|
||||
fork2.release()
|
||||
fork1.release()
|
||||
|
||||
def dining(self):
|
||||
print '%s starts eating '% self.name
|
||||
time.sleep(random.uniform(1,10))
|
||||
print '%s finishes eating and leaves to think.' % self.name
|
||||
|
||||
def DiningPhilosophers():
|
||||
forks = [threading.Lock() for n in range(5)]
|
||||
philosopherNames = ('Aristotle','Kant','Spinoza','Marx', 'Russel')
|
||||
|
||||
philosophers= [Philosopher(philosopherNames[i], forks[i%5], forks[(i+1)%5]) \
|
||||
for i in range(5)]
|
||||
|
||||
random.seed(507129)
|
||||
Philosopher.running = True
|
||||
for p in philosophers: p.start()
|
||||
time.sleep(100)
|
||||
Philosopher.running = False
|
||||
print ("Now we're finishing.")
|
||||
|
||||
DiningPhilosophers()
|
||||
48
Task/Dining-philosophers/REXX/dining-philosophers.rexx
Normal file
48
Task/Dining-philosophers/REXX/dining-philosophers.rexx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*REXX program demonstrates a solution in solving the dining philosophers problem. */
|
||||
signal on halt /*branches to HALT: (on Ctrl─break).*/
|
||||
parse arg seed diners /*obtain optional arguments from the CL*/
|
||||
if datatype(seed, 'W') then call random ,, seed /*this allows for random repeatability.*/
|
||||
if diners= '' then diners = 'Aristotle, Kant, Spinoza, Marx, Russell'
|
||||
tell= left(seed, 1) \== '+' /*Leading + in SEED? Then no statistics*/
|
||||
diners= space( translate(diners, , ',') ) /*change to an uncommatized diners list*/
|
||||
#= words(diners); @.= 0 /*#: the number of dining philosophers.*/
|
||||
eatL= 15; eatH= 60 /*minimum & maximum minutes for eating.*/
|
||||
thinkL= 30; thinkH= 180 /* " " " " " thinking*/
|
||||
forks.= 1 /*indicate that all forks are on table.*/
|
||||
do tic=1 /*'til halted.*/ /*use "minutes" for time advancement.*/
|
||||
call grabForks /*determine if anybody can grab 2 forks*/
|
||||
call passTime /*handle philosophers eating|thinking. */
|
||||
end /*tic*/ /* ··· and time marches on ··· */
|
||||
/* [↓] this REXX program was halted,*/
|
||||
halt: say ' ··· REXX program halted!' /*probably by Ctrl─Break or equivalent.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
fork: parse arg x 1 ox; x= abs(x) ; L= x - 1 ; if L==0 then L= # /*use "round Robin"*/
|
||||
if ox<0 then do; forks.L= 1; forks.x=1; return; end /*drop the forks. */
|
||||
got2= forks.L & forks.x /*get 2 forks │ not*/
|
||||
if got2 then do; forks.L= 0; forks.x=0; end /*obtained 2 forks */
|
||||
return got2 /*return with success ··· or failure. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
grabForks: do person=1 for # /*see if any person can grab two forks.*/
|
||||
if @.person.state\==0 then iterate /*this diner ain't in a waiting state. */
|
||||
if \fork(person) then iterate /* " " didn't grab two forks. */
|
||||
@.person.state= 'eating' /* " " is slurping spaghetti. */
|
||||
@.person.dur= random(eatL, eatH) /*how long will this diner eat pasta ? */
|
||||
end /*person*/ /* [↑] process the dining philosophers*/
|
||||
return /*all the diners have been examined. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
passTime: if tell then say /*display a handy blank line separator.*/
|
||||
do p=1 for # /*handle each of the diner's activity. */
|
||||
if tell then say right(tic, 9, .) right( word( diners, p), 20),
|
||||
right(word(@.p.state 'waiting',1+(@.p.state==0)),9) right(@.p.dur,5)
|
||||
if @.p.dur==0 then iterate /*this diner is waiting for two forks. */
|
||||
@.p.dur= @.p.dur - 1 /*indicate single time unit has passed.*/
|
||||
if @.p.dur\==0 then iterate /*Activity done? No, then keep it up.*/
|
||||
if @.p.state=='eating' then do /*now, leave the table.*/
|
||||
call fork -p /*drop the darn forks. */
|
||||
@.p.state= 'thinking' /*status.*/
|
||||
@.p.dur= random(thinkL, thinkH) /*length.*/
|
||||
end /* [↓] a diner goes ──► the table. */
|
||||
else if @.p.state=='thinking' then @.p.state=0
|
||||
end /*p*/ /*[↑] P (person)≡ dining philosophers.*/
|
||||
return /*now, have some human beans grab forks*/
|
||||
87
Task/Dining-philosophers/Racket/dining-philosophers.rkt
Normal file
87
Task/Dining-philosophers/Racket/dining-philosophers.rkt
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#lang racket
|
||||
|
||||
;; Racket has traditional semaphores in addition to several higher level
|
||||
;; synchronization tools. (Note that these semaphores are used for Racket's
|
||||
;; green-threads, there are also "future semaphores" which are used for OS
|
||||
;; threads, with a similar interface.)
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; First, a bunch of code to run the experiments below
|
||||
|
||||
;; Only two philosophers to make it deadlock very fast
|
||||
(define philosophers '(Aristotle Kant #|Spinoza Marx Russell|#))
|
||||
|
||||
(define (run-philosopher name fork1 fork2)
|
||||
(define (show what) (displayln (~a name " " what)))
|
||||
(define (loop)
|
||||
(show "thinks") (sleep (* 2 (random))) (show "is hungry")
|
||||
(grab-forks fork1 fork2 (λ() (show "eats") (sleep (random))))
|
||||
(loop))
|
||||
(thread loop))
|
||||
|
||||
(define (run:simple)
|
||||
(define forks (for/list ([i philosophers]) (make-semaphore 1)))
|
||||
(for ([i philosophers] [fork1 forks] [fork2 (cons (last forks) forks)])
|
||||
(run-philosopher i fork1 fork2))
|
||||
(sleep (* 60 60 24 365)))
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; This is the naive implementation, which can be used to try getting a
|
||||
;; deadlock.
|
||||
|
||||
(define (grab:naive fork1 fork2 eat!)
|
||||
(semaphore-wait fork1)
|
||||
(sleep (random)) ; to make deadlocks probable
|
||||
(semaphore-wait fork2)
|
||||
(eat!)
|
||||
(semaphore-post fork1)
|
||||
(semaphore-post fork2))
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; One way to solve it is to release the first fork if the second is busy and
|
||||
;; wait for a while.
|
||||
|
||||
(define (grab:release+wait fork1 fork2 eat!)
|
||||
(semaphore-wait fork1)
|
||||
(if (not (semaphore-try-wait? fork2))
|
||||
;; couldn't grab the second fork, so release the first and wait
|
||||
(begin (semaphore-post fork1)
|
||||
(sleep (random))
|
||||
(grab-forks fork1 fork2)) ; can swap them to improve chances
|
||||
;; we have both forks
|
||||
(begin (eat!)
|
||||
(semaphore-post fork1)
|
||||
(semaphore-post fork2))))
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; Another solution is to label the forks and lock the lowest-id one first,
|
||||
;; which makes the naive solution work.
|
||||
|
||||
(define (run:labeled-forks)
|
||||
(define forks (for/list ([i philosophers]) (make-semaphore 1)))
|
||||
;; the simple run used forks as (1 2 3 4) (4 1 2 3) -- so to implement this,
|
||||
;; we can swap the two first ones: (4 2 3 4) (1 1 2 3)
|
||||
(for ([i philosophers]
|
||||
[fork1 (cons (last forks) (cdr forks))]
|
||||
[fork2 (cons (first forks) forks)])
|
||||
(run-philosopher i fork1 fork2))
|
||||
(sleep (* 60 60 24 365)))
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; Homework: implement the centralized waiter solution
|
||||
|
||||
;; ...
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; Uncomment one of the following pairs to try it
|
||||
|
||||
;; (define grab-forks grab:naive)
|
||||
;; (define run run:simple)
|
||||
|
||||
;; (define grab-forks grab:release+wait)
|
||||
;; (define run run:simple)
|
||||
|
||||
;; (define grab-forks grab:naive)
|
||||
;; (define run run:labeled-forks)
|
||||
|
||||
(run)
|
||||
51
Task/Dining-philosophers/Raku/dining-philosophers.raku
Normal file
51
Task/Dining-philosophers/Raku/dining-philosophers.raku
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
class Fork {
|
||||
has $!lock = Lock.new;
|
||||
method grab($who, $which) {
|
||||
say "$who grabbing $which fork";
|
||||
$!lock.lock;
|
||||
}
|
||||
method drop($who, $which) {
|
||||
say "$who dropping $which fork";
|
||||
$!lock.unlock;
|
||||
}
|
||||
}
|
||||
|
||||
class Lollipop {
|
||||
has $!channel = Channel.new;
|
||||
method mine($who) { $!channel.send($who) }
|
||||
method yours { $!channel.receive }
|
||||
}
|
||||
|
||||
sub dally($sec) { sleep 0.01 + rand * $sec }
|
||||
|
||||
sub MAIN(*@names) {
|
||||
@names ||= <Aristotle Kant Spinoza Marx Russell>;
|
||||
|
||||
my @lfork = Fork.new xx @names;
|
||||
my @rfork = @lfork.rotate;
|
||||
|
||||
my $lollipop = Lollipop.new;
|
||||
start { $lollipop.yours; }
|
||||
|
||||
my @philosophers = do for flat @names Z @lfork Z @rfork -> $n, $l, $r {
|
||||
start {
|
||||
sleep 1 + rand*4;
|
||||
loop {
|
||||
$l.grab($n,'left');
|
||||
dally 1; # give opportunity for deadlock
|
||||
$r.grab($n,'right');
|
||||
say "$n eating";
|
||||
dally 10;
|
||||
$l.drop($n,'left');
|
||||
$r.drop($n,'right');
|
||||
|
||||
$lollipop.mine($n);
|
||||
sleep 1; # lick at least once
|
||||
say "$n lost lollipop to $lollipop.yours(), now digesting";
|
||||
|
||||
dally 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
sink await @philosophers;
|
||||
}
|
||||
70
Task/Dining-philosophers/Ruby/dining-philosophers.rb
Normal file
70
Task/Dining-philosophers/Ruby/dining-philosophers.rb
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
require 'mutex_m'
|
||||
|
||||
class Philosopher
|
||||
def initialize(name, left_fork, right_fork)
|
||||
@name = name
|
||||
@left_fork = left_fork
|
||||
@right_fork = right_fork
|
||||
@meals = 0
|
||||
end
|
||||
|
||||
def go
|
||||
while @meals < 5
|
||||
think
|
||||
dine
|
||||
end
|
||||
puts "philosopher #@name is full!"
|
||||
end
|
||||
|
||||
def think
|
||||
puts "philosopher #@name is thinking..."
|
||||
sleep(rand())
|
||||
puts "philosopher #@name is hungry..."
|
||||
end
|
||||
|
||||
def dine
|
||||
fork1, fork2 = @left_fork, @right_fork
|
||||
while true
|
||||
pickup(fork1, :wait => true)
|
||||
puts "philosopher #@name has fork #{fork1.fork_id}..."
|
||||
if pickup(fork2, :wait => false)
|
||||
break
|
||||
end
|
||||
puts "philosopher #@name cannot pickup second fork #{fork2.fork_id}..."
|
||||
release(fork1)
|
||||
fork1, fork2 = fork2, fork1
|
||||
end
|
||||
puts "philosopher #@name has the second fork #{fork2.fork_id}..."
|
||||
|
||||
puts "philosopher #@name eats..."
|
||||
sleep(rand())
|
||||
puts "philosopher #@name belches"
|
||||
@meals += 1
|
||||
|
||||
release(@left_fork)
|
||||
release(@right_fork)
|
||||
end
|
||||
|
||||
def pickup(fork, opt)
|
||||
puts "philosopher #@name attempts to pickup fork #{fork.fork_id}..."
|
||||
opt[:wait] ? fork.mutex.mu_lock : fork.mutex.mu_try_lock
|
||||
end
|
||||
|
||||
def release(fork)
|
||||
puts "philosopher #@name releases fork #{fork.fork_id}..."
|
||||
fork.mutex.unlock
|
||||
end
|
||||
end
|
||||
|
||||
n = 5
|
||||
|
||||
Fork = Struct.new(:fork_id, :mutex)
|
||||
forks = Array.new(n) {|i| Fork.new(i, Object.new.extend(Mutex_m))}
|
||||
|
||||
philosophers = Array.new(n) do |i|
|
||||
Thread.new(i, forks[i], forks[(i+1)%n]) do |id, f1, f2|
|
||||
ph = Philosopher.new(id, f1, f2).go
|
||||
end
|
||||
end
|
||||
|
||||
philosophers.each {|thread| thread.join}
|
||||
63
Task/Dining-philosophers/Rust/dining-philosophers.rust
Normal file
63
Task/Dining-philosophers/Rust/dining-philosophers.rust
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use std::thread;
|
||||
use std::sync::{Mutex, Arc};
|
||||
|
||||
struct Philosopher {
|
||||
name: String,
|
||||
left: usize,
|
||||
right: usize,
|
||||
}
|
||||
|
||||
impl Philosopher {
|
||||
fn new(name: &str, left: usize, right: usize) -> Philosopher {
|
||||
Philosopher {
|
||||
name: name.to_string(),
|
||||
left: left,
|
||||
right: right,
|
||||
}
|
||||
}
|
||||
|
||||
fn eat(&self, table: &Table) {
|
||||
let _left = table.forks[self.left].lock().unwrap();
|
||||
let _right = table.forks[self.right].lock().unwrap();
|
||||
|
||||
println!("{} is eating.", self.name);
|
||||
|
||||
thread::sleep_ms(1000);
|
||||
|
||||
println!("{} is done eating.", self.name);
|
||||
}
|
||||
}
|
||||
|
||||
struct Table {
|
||||
forks: Vec<Mutex<()>>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let table = Arc::new(Table { forks: vec![
|
||||
Mutex::new(()),
|
||||
Mutex::new(()),
|
||||
Mutex::new(()),
|
||||
Mutex::new(()),
|
||||
Mutex::new(()),
|
||||
]});
|
||||
|
||||
let philosophers = vec![
|
||||
Philosopher::new("Baruch Spinoza", 0, 1),
|
||||
Philosopher::new("Gilles Deleuze", 1, 2),
|
||||
Philosopher::new("Karl Marx", 2, 3),
|
||||
Philosopher::new("Friedrich Nietzsche", 3, 4),
|
||||
Philosopher::new("Michel Foucault", 0, 4),
|
||||
];
|
||||
|
||||
let handles: Vec<_> = philosophers.into_iter().map(|p| {
|
||||
let table = table.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
p.eat(&table);
|
||||
})
|
||||
}).collect();
|
||||
|
||||
for h in handles {
|
||||
h.join().unwrap();
|
||||
}
|
||||
}
|
||||
162
Task/Dining-philosophers/Simula/dining-philosophers.simula
Normal file
162
Task/Dining-philosophers/Simula/dining-philosophers.simula
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
COMMENT
|
||||
! DEADLOCK IS PREVENTED BY REVERSING THE ORDER OF TAKING THE CHOPSTICKS FOR THE LAST PHILOSOPHER.
|
||||
! THAT MEANS ALL PHILOSOPHERS FIRST TAKE THE LEFT CHOPSTICK, THEN THE RIGHT CHOPSTICK.
|
||||
! BUT THE LAST PHILOSOPHER FIRST TAKES THE RIGHT CHOPSTICK, THEN THE LEFT.
|
||||
!
|
||||
! THE DETACH STATEMENT IN CLASS PHILOSOPHER GIVES CONTROL BACK TO THE MAIN BLOCK.
|
||||
! THE MAIN BLOCK CALLS/RESUMES ALL THE PHILOSOPHERS USING THE RESUME(PHILOSOPHER) STATEMENT.
|
||||
! THIS CONTINUES THE CODE IN THE PHILOSOPHER CLASS AFTER THE LAST DETACH STATEMENT.
|
||||
! (ANOTHER NAME FOR THIS FEATURE IS THE CONCEPT OF A COROUTINE)
|
||||
;
|
||||
BEGIN
|
||||
INTEGER N;
|
||||
INTEGER PNR, CNR;
|
||||
INTEGER SEED;
|
||||
SEED := ININT;
|
||||
N := 5;
|
||||
BEGIN
|
||||
|
||||
CLASS CHOPSTICK;
|
||||
BEGIN
|
||||
REF(PHILOSOPHER) OWNER;
|
||||
INTEGER ID;
|
||||
ID := CNR := CNR + 1;
|
||||
END CHOPSTICK;
|
||||
|
||||
CLASS PHILOSOPHER(L,R);
|
||||
REF(CHOPSTICK) L,R;
|
||||
BEGIN
|
||||
INTEGER ID;
|
||||
ID := PNR := PNR + 1;
|
||||
WHILE TRUE DO
|
||||
BEGIN
|
||||
DETACH;
|
||||
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") THINKING...");
|
||||
OUTIMAGE;
|
||||
DETACH;
|
||||
|
||||
WHILE RANDINT(0,1,SEED) = 0 DO BEGIN
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") THINKING DEEPER...");
|
||||
OUTIMAGE;
|
||||
DETACH;
|
||||
END;
|
||||
|
||||
WHILE L.OWNER =/= NONE DO BEGIN
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") WAITING FOR LEFT CHOPSTICK(");
|
||||
OUTINT(L.ID, 0);
|
||||
OUTTEXT(") ...");
|
||||
OUTIMAGE;
|
||||
DETACH;
|
||||
END;
|
||||
L.OWNER :- THIS PHILOSOPHER;
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") GRABBED LEFT CHOPSTICK(");
|
||||
OUTINT(L.ID, 0);
|
||||
OUTTEXT(")");
|
||||
OUTIMAGE;
|
||||
|
||||
WHILE R.OWNER =/= NONE DO BEGIN
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") WAITING FOR RIGHT CHOPSTICK(");
|
||||
OUTINT(R.ID, 0);
|
||||
OUTTEXT(") ...");
|
||||
OUTIMAGE;
|
||||
DETACH;
|
||||
END;
|
||||
R.OWNER :- THIS PHILOSOPHER;
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") GRABBED RIGHT CHOPSTICK(");
|
||||
OUTINT(R.ID, 0);
|
||||
OUTTEXT(")");
|
||||
OUTIMAGE;
|
||||
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") EATING...");
|
||||
OUTIMAGE;
|
||||
WHILE RANDINT(0,1,SEED) = 0 DO BEGIN
|
||||
DETACH;
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") STILL EATING...");
|
||||
OUTIMAGE;
|
||||
END;
|
||||
L.OWNER :- NONE;
|
||||
R.OWNER :- NONE;
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") RELEASED LEFT CHOPSTICK(");
|
||||
OUTINT(L.ID, 0);
|
||||
OUTTEXT(")");
|
||||
OUTIMAGE;
|
||||
OUTTEXT("PHILOSOPHER(");
|
||||
OUTINT(ID, 0);
|
||||
OUTTEXT(") RELEASED RIGHT CHOPSTICK(");
|
||||
OUTINT(R.ID, 0);
|
||||
OUTTEXT(")");
|
||||
OUTIMAGE;
|
||||
END;
|
||||
END PHILOSOPHER;
|
||||
|
||||
!---------------------------------------|
|
||||
! |
|
||||
! |
|
||||
! (3) |
|
||||
! P2 P3 |
|
||||
! |
|
||||
! (2) (4) |
|
||||
! |
|
||||
! |
|
||||
! P1 P4 |
|
||||
! |
|
||||
! |
|
||||
! (1) (5) |
|
||||
! |
|
||||
! P5 | only P5 takes Right first (5), then Left (1)
|
||||
! |
|
||||
!---------------------------------------|
|
||||
!;
|
||||
|
||||
REF(PHILOSOPHER) ARRAY PHILS (1:N);
|
||||
REF(CHOPSTICK) L, R;
|
||||
INTEGER I, LOOPS;
|
||||
|
||||
R :- NEW CHOPSTICK;
|
||||
FOR I := 1 STEP 1 UNTIL N-1 DO
|
||||
BEGIN
|
||||
L :- NEW CHOPSTICK;
|
||||
PHILS(I) :- NEW PHILOSOPHER(L,R);
|
||||
R :- L;
|
||||
END;
|
||||
! REVERSED ORDER FOR THE LAST PHILOSOPHER ;
|
||||
PHILS(N) :- NEW PHILOSOPHER(R,PHILS(1).R);
|
||||
|
||||
FOR I := 1 STEP 1 UNTIL N DO BEGIN
|
||||
OUTTEXT("PHILOSOPHER(ID=");
|
||||
OUTINT(PHILS(I).ID, 0);
|
||||
OUTTEXT(", L=");
|
||||
OUTINT(PHILS(I).L.ID, 0);
|
||||
OUTTEXT(", R=");
|
||||
OUTINT(PHILS(I).R.ID, 0);
|
||||
OUTTEXT(")");
|
||||
OUTIMAGE;
|
||||
END;
|
||||
|
||||
FOR LOOPS := 1 STEP 1 UNTIL 10 DO BEGIN
|
||||
FOR I := 1 STEP 1 UNTIL N DO BEGIN
|
||||
RESUME(PHILS(I));
|
||||
END;
|
||||
END;
|
||||
|
||||
END;
|
||||
END.
|
||||
97
Task/Dining-philosophers/Smalltalk/dining-philosophers.st
Normal file
97
Task/Dining-philosophers/Smalltalk/dining-philosophers.st
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 13 October 2011 at 2:44:42 pm'!
|
||||
Object subclass: #Philosopher
|
||||
instanceVariableNames: 'table random name seat forks running'
|
||||
classVariableNames: ''
|
||||
poolDictionaries: ''
|
||||
category: 'rosettacode'!
|
||||
|
||||
!Philosopher methodsFor: 'private'!
|
||||
createfork
|
||||
^ Semaphore forMutualExclusion! !
|
||||
|
||||
!Philosopher methodsFor: 'private'!
|
||||
displayState: aStateName
|
||||
Transcript show: name , ' is ' , aStateName;
|
||||
cr! !
|
||||
|
||||
!Philosopher methodsFor: 'private'!
|
||||
pickUpForkAt: relativePosition
|
||||
| fork pos |
|
||||
pos := self tableIndex: seat + relativePosition.
|
||||
(fork := table at: pos)
|
||||
ifNotNil: [fork
|
||||
critical: [(table at: pos) notNil
|
||||
ifTrue: [table at: pos put: nil]
|
||||
ifFalse: [fork := nil]]].
|
||||
^ (forks at: relativePosition put: fork) notNil! !
|
||||
|
||||
!Philosopher methodsFor: 'private'!
|
||||
putBackForkAt: aRelativePosition
|
||||
| fork |
|
||||
fork := forks at: aRelativePosition.
|
||||
fork
|
||||
ifNotNil: [table
|
||||
at: (self tableIndex: seat + aRelativePosition)
|
||||
put: fork.
|
||||
forks at: aRelativePosition put: nil]! !
|
||||
|
||||
!Philosopher methodsFor: 'private'!
|
||||
tableIndex: aNum
|
||||
^ aNum - 1 \\ table size + 1! !
|
||||
|
||||
!Philosopher methodsFor: 'private'!
|
||||
waitRandomTime
|
||||
(Delay forMilliseconds: (random next * 4000) rounded) wait! !
|
||||
|
||||
|
||||
!Philosopher methodsFor: 'dining'!
|
||||
eat
|
||||
self displayState: 'eating';
|
||||
waitRandomTime;
|
||||
putBackForkAt: -1;
|
||||
putBackForkAt: 1! !
|
||||
|
||||
!Philosopher methodsFor: 'dining'!
|
||||
pickUpForks
|
||||
self displayState: 'trying to pick up forks'.
|
||||
[(self pickUpForkAt: -1)
|
||||
ifTrue: [(self pickUpForkAt: 1)
|
||||
ifFalse: [self putBackForkAt: -1]].
|
||||
(forks at: 1) notNil]
|
||||
whileFalse: [(Delay forMilliseconds: 10) wait]! !
|
||||
|
||||
!Philosopher methodsFor: 'dining'!
|
||||
think
|
||||
self displayState: 'thinking';
|
||||
waitRandomTime! !
|
||||
|
||||
|
||||
!Philosopher methodsFor: 'initialize-release'!
|
||||
beginDining: aName at: aTable
|
||||
name := aName.
|
||||
table := aTable.
|
||||
forks := Dictionary new at: -1 put: nil;
|
||||
at: 1 put: nil;
|
||||
yourself.
|
||||
random := Random new seed: name hash.
|
||||
seat := table size + 1.
|
||||
table add: self;
|
||||
add: self createfork.
|
||||
running := true.
|
||||
[(Delay forSeconds: 20) wait.
|
||||
running := false] fork.
|
||||
[[running]
|
||||
whileTrue: [self think; pickUpForks; eat].
|
||||
nil] fork! !
|
||||
|
||||
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
|
||||
|
||||
Philosopher class
|
||||
instanceVariableNames: ''!
|
||||
|
||||
!Philosopher class methodsFor: 'examples'!
|
||||
diningPhilosophersTest
|
||||
| diningTable |
|
||||
diningTable := OrderedCollection new.
|
||||
#('Aristotle' 'Kant' 'Buddha' 'Marx' 'Russel' )
|
||||
do: [:aName | Philosopher new beginDining: aName at: diningTable]! !
|
||||
68
Task/Dining-philosophers/Tcl/dining-philosophers.tcl
Normal file
68
Task/Dining-philosophers/Tcl/dining-philosophers.tcl
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package require Thread
|
||||
|
||||
foreach name {Aristotle Kant Spinoza Marx Russel} {
|
||||
lappend forks [thread::mutex create]
|
||||
lappend tasks [set t [thread::create -preserved {
|
||||
# Implement each task as a coroutine internally for simplicity of presentation
|
||||
# This is because we want to remain able to receive messages so we can shut
|
||||
# down neatly at the end of the program.
|
||||
interp alias {} doTask {} coroutine t philosopher
|
||||
proc delay {expression} {
|
||||
yield [after [expr $expression] [info coroutine]]
|
||||
}
|
||||
|
||||
# Forks are mutexes...
|
||||
proc pickUpFork fork {
|
||||
thread::mutex lock $fork
|
||||
}
|
||||
proc putDownFork fork {
|
||||
thread::mutex unlock $fork
|
||||
}
|
||||
|
||||
# The actual implementation of the task
|
||||
proc philosopher {f1 f2} {
|
||||
global name
|
||||
# Always acquire forks in order; prevents deadlock
|
||||
# Uses the "natural" order of the lexicographical order of the fork names
|
||||
if {$f1 > $f2} {
|
||||
lassign [list $f1 $f2] f2 f1
|
||||
}
|
||||
|
||||
# The classic "philosophers" loop
|
||||
while {true} {
|
||||
puts "$name is thinking"
|
||||
delay {int(200*rand())}
|
||||
|
||||
puts "$name is hungry, getting fork in left hand"
|
||||
pickUpFork $f1
|
||||
delay {int(2000*rand())} ;# Make deadlock likely if it is possible!
|
||||
|
||||
puts "$name is hungry, getting fork in right hand"
|
||||
pickUpFork $f2
|
||||
|
||||
puts "$name is eating"
|
||||
delay {int(2000*rand())}
|
||||
|
||||
puts "$name has finished eating; putting down forks"
|
||||
putDownFork $f2
|
||||
putDownFork $f1
|
||||
delay 100
|
||||
}
|
||||
}
|
||||
thread::wait
|
||||
}]]
|
||||
thread::send $t [list set name $name]
|
||||
}
|
||||
|
||||
# Set the tasks going
|
||||
foreach t $tasks {f1 f2} {0 1 1 2 2 3 3 4 4 0} {
|
||||
thread::send -async $t [list \
|
||||
doTask [lindex $forks $f1] [lindex $forks $f2]]
|
||||
}
|
||||
|
||||
# Kill everything off after 30 seconds; that's enough for demonstration!
|
||||
after 30000
|
||||
puts "Completing..."
|
||||
foreach t $tasks {
|
||||
thread::send -async $t thread::exit
|
||||
}
|
||||
96
Task/Dining-philosophers/VBA/dining-philosophers.vba
Normal file
96
Task/Dining-philosophers/VBA/dining-philosophers.vba
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
'The combination of holding to the second fork
|
||||
'(HOLDON=True) and all philosophers start
|
||||
'with same hand (DIJKSTRASOLUTION=False) leads
|
||||
'to a deadlock. To prevent deadlock
|
||||
'set HOLDON=False, and DIJKSTRASOLUTION=True.
|
||||
Public Const HOLDON = False
|
||||
Public Const DIJKSTRASOLUTION = True
|
||||
Public Const X = 10 'chance to continue eating/thinking
|
||||
Public Const GETS = 0
|
||||
Public Const PUTS = 1
|
||||
Public Const EATS = 2
|
||||
Public Const THKS = 5
|
||||
Public Const FRSTFORK = 0
|
||||
Public Const SCNDFORK = 1
|
||||
Public Const SPAGHETI = 0
|
||||
Public Const UNIVERSE = 1
|
||||
Public Const MAXCOUNT = 100000
|
||||
Public Const PHILOSOPHERS = 5
|
||||
Public semaphore(PHILOSOPHERS - 1) As Integer
|
||||
Public positi0n(1, PHILOSOPHERS - 1) As Integer
|
||||
Public programcounter(PHILOSOPHERS - 1) As Long
|
||||
Public statistics(PHILOSOPHERS - 1, 5, 1) As Long
|
||||
Public names As Variant
|
||||
Private Sub init()
|
||||
names = [{"Aquinas","Babbage","Carroll","Derrida","Erasmus"}]
|
||||
For j = 0 To PHILOSOPHERS - 2
|
||||
positi0n(0, j) = j + 1 'first fork in right hand
|
||||
positi0n(1, j) = j 'second fork in left hand
|
||||
Next j
|
||||
If DIJKSTRASOLUTION Then
|
||||
positi0n(0, PHILOSOPHERS - 1) = j ' first fork in left hand
|
||||
positi0n(1, PHILOSOPHERS - 1) = 0 'second fork in right hand
|
||||
Else
|
||||
positi0n(0, PHILOSOPHERS - 1) = 0 'first fork in right hand
|
||||
positi0n(1, PHILOSOPHERS - 1) = j 'second fork in left hand
|
||||
End If
|
||||
End Sub
|
||||
Private Sub philosopher(subject As Integer, verb As Integer, objekt As Integer)
|
||||
statistics(subject, verb, objekt) = statistics(subject, verb, objekt) + 1
|
||||
If verb < 2 Then
|
||||
If semaphore(positi0n(objekt, subject)) <> verb Then
|
||||
If Not HOLDON Then
|
||||
'can't get a fork, release first fork if subject has it, and
|
||||
'this won't toggle the semaphore if subject hasn't firt fork
|
||||
semaphore(positi0n(FRSTFORK, subject)) = 1 - objekt
|
||||
'next round back to try to get first fork
|
||||
programcounter(subject) = 0
|
||||
End If
|
||||
Else
|
||||
'just toggle semaphore and move on
|
||||
semaphore(positi0n(objekt, subject)) = 1 - verb
|
||||
programcounter(subject) = (programcounter(subject) + 1) Mod 6
|
||||
End If
|
||||
Else
|
||||
'when eating or thinking, (100*(X-1)/X)% continue eating or thinking
|
||||
'(100/X)% advance program counter
|
||||
programcounter(subject) = IIf(X * Rnd > 1, verb, verb + 1) Mod 6
|
||||
End If
|
||||
End Sub
|
||||
Private Sub dine()
|
||||
Dim ph As Integer
|
||||
Do While TC < MAXCOUNT
|
||||
For ph = 0 To PHILOSOPHERS - 1
|
||||
Select Case programcounter(ph)
|
||||
Case 0: philosopher ph, GETS, FRSTFORK
|
||||
Case 1: philosopher ph, GETS, SCNDFORK
|
||||
Case 2: philosopher ph, EATS, SPAGHETI
|
||||
Case 3: philosopher ph, PUTS, FRSTFORK
|
||||
Case 4: philosopher ph, PUTS, SCNDFORK
|
||||
Case 5: philosopher ph, THKS, UNIVERSE
|
||||
End Select
|
||||
TC = TC + 1
|
||||
Next ph
|
||||
Loop
|
||||
End Sub
|
||||
Private Sub show()
|
||||
Debug.Print "Stats", "Gets", "Gets", "Eats", "Puts", "Puts", "Thinks"
|
||||
Debug.Print "", "First", "Second", "Spag-", "First", "Second", "About"
|
||||
Debug.Print "", "Fork", "Fork", "hetti", "Fork", "Fork", "Universe"
|
||||
For subject = 0 To PHILOSOPHERS - 1
|
||||
Debug.Print names(subject + 1),
|
||||
For objekt = 0 To 1
|
||||
Debug.Print statistics(subject, GETS, objekt),
|
||||
Next objekt
|
||||
Debug.Print statistics(subject, EATS, SPAGHETI),
|
||||
For objekt = 0 To 1
|
||||
Debug.Print statistics(subject, PUTS, objekt),
|
||||
Next objekt
|
||||
Debug.Print statistics(subject, THKS, UNIVERSE)
|
||||
Next subject
|
||||
End Sub
|
||||
Public Sub main()
|
||||
init
|
||||
dine
|
||||
show
|
||||
End Sub
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
Imports System.Threading
|
||||
Module Module1
|
||||
Public rnd As New Random
|
||||
|
||||
Sub Main()
|
||||
'Aristotle, Kant, Spinoza, Marx, and Russel
|
||||
Dim f1 As New Fork(1)
|
||||
Dim f2 As New Fork(2)
|
||||
Dim f3 As New Fork(3)
|
||||
Dim f4 As New Fork(4)
|
||||
Dim f5 As New Fork(5)
|
||||
|
||||
Console.WriteLine("1: Deadlock")
|
||||
Console.WriteLine("2: Live lock")
|
||||
Console.WriteLine("3: Working")
|
||||
Select Console.ReadLine
|
||||
Case "1"
|
||||
Using _
|
||||
Aristotle As New SelfishPhilosopher("Aristotle", f1, f2), _
|
||||
Kant As New SelfishPhilosopher("Kant", f2, f3), _
|
||||
Spinoza As New SelfishPhilosopher("Spinoza", f3, f4), _
|
||||
Marx As New SelfishPhilosopher("Marx", f4, f5), _
|
||||
Russel As New SelfishPhilosopher("Russel", f5, f1)
|
||||
|
||||
Console.ReadLine()
|
||||
End Using
|
||||
Case "2"
|
||||
Using _
|
||||
Aristotle As New SelflessPhilosopher("Aristotle", f1, f2), _
|
||||
Kant As New SelflessPhilosopher("Kant", f2, f3), _
|
||||
Spinoza As New SelflessPhilosopher("Spinoza", f3, f4), _
|
||||
Marx As New SelflessPhilosopher("Marx", f4, f5), _
|
||||
Russel As New SelflessPhilosopher("Russel", f5, f1)
|
||||
|
||||
Console.ReadLine()
|
||||
End Using
|
||||
Case "3"
|
||||
Using _
|
||||
Aristotle As New WisePhilosopher("Aristotle", f1, f2), _
|
||||
Kant As New WisePhilosopher("Kant", f2, f3), _
|
||||
Spinoza As New WisePhilosopher("Spinoza", f3, f4), _
|
||||
Marx As New WisePhilosopher("Marx", f4, f5), _
|
||||
Russel As New WisePhilosopher("Russel", f5, f1)
|
||||
|
||||
Console.ReadLine()
|
||||
End Using
|
||||
End Select
|
||||
End Sub
|
||||
|
||||
End Module
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
Class Fork
|
||||
Private ReadOnly m_Number As Integer
|
||||
Public Sub New(ByVal number As Integer)
|
||||
m_Number = number
|
||||
End Sub
|
||||
Public ReadOnly Property Number() As Integer
|
||||
Get
|
||||
Return m_Number
|
||||
End Get
|
||||
End Property
|
||||
End Class
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
MustInherit Class PhilosopherBase
|
||||
Implements IDisposable
|
||||
|
||||
Protected m_Disposed As Boolean
|
||||
Protected ReadOnly m_Left As Fork
|
||||
Protected ReadOnly m_Right As Fork
|
||||
Protected ReadOnly m_Name As String
|
||||
Public Sub New(ByVal name As String, ByVal right As Fork, ByVal left As Fork)
|
||||
m_Name = name
|
||||
m_Right = right
|
||||
m_Left = left
|
||||
Dim t As New Thread(AddressOf MainLoop)
|
||||
t.IsBackground = True
|
||||
t.Start()
|
||||
End Sub
|
||||
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
|
||||
m_Disposed = True
|
||||
End Sub
|
||||
|
||||
Public Sub Dispose() Implements IDisposable.Dispose
|
||||
Dispose(True)
|
||||
GC.SuppressFinalize(Me)
|
||||
End Sub
|
||||
Public ReadOnly Property Name() As String
|
||||
Get
|
||||
Return m_Name
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public MustOverride Sub MainLoop()
|
||||
End Class
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
Class SelfishPhilosopher
|
||||
Inherits PhilosopherBase
|
||||
Public Sub New(ByVal name As String, ByVal right As Fork, ByVal left As Fork)
|
||||
MyBase.New(name, right, left)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub MainLoop()
|
||||
Do
|
||||
Console.WriteLine(Name & " sat down")
|
||||
SyncLock m_Left
|
||||
Console.WriteLine(Name & " picked up fork " & m_Left.Number)
|
||||
|
||||
SyncLock m_Right
|
||||
Console.WriteLine(Name & " picked up fork " & m_Right.Number)
|
||||
|
||||
Console.WriteLine(Name & " ate!!!!")
|
||||
|
||||
Console.WriteLine(Name & " put down fork " & m_Right.Number)
|
||||
End SyncLock
|
||||
|
||||
|
||||
Console.WriteLine(Name & " put down fork " & m_Left.Number)
|
||||
End SyncLock
|
||||
|
||||
Console.WriteLine(Name & " stood up")
|
||||
|
||||
Thread.Sleep(rnd.Next(0, 10000))
|
||||
Loop Until m_Disposed
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Class SelflessPhilosopher
|
||||
Inherits PhilosopherBase
|
||||
|
||||
Public Sub New(ByVal name As String, ByVal right As Fork, ByVal left As Fork)
|
||||
MyBase.New(name, right, left)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub MainLoop()
|
||||
Do
|
||||
Console.WriteLine(Name & " sat down")
|
||||
Dim needDelay = False
|
||||
TryAgain:
|
||||
If needDelay Then Thread.Sleep(rnd.Next(0, 10000))
|
||||
Try
|
||||
Monitor.Enter(m_Left)
|
||||
Console.WriteLine(Name & " picked up fork " & m_Left.Number)
|
||||
|
||||
If Monitor.TryEnter(m_Right) Then
|
||||
Console.WriteLine(Name & " picked up fork " & m_Right.Number)
|
||||
|
||||
Console.WriteLine(Name & " ate!!!!!!")
|
||||
|
||||
Console.WriteLine(Name & " put down fork " & m_Right.Number)
|
||||
Monitor.Exit(m_Right)
|
||||
Else
|
||||
Console.WriteLine(Name & " is going to wait")
|
||||
needDelay = True
|
||||
GoTo TryAgain
|
||||
End If
|
||||
Finally
|
||||
Console.WriteLine(Name & " put down fork " & m_Left.Number)
|
||||
End Try
|
||||
|
||||
Console.WriteLine(Name & " stood up")
|
||||
|
||||
Thread.Sleep(rnd.Next(0, 10000))
|
||||
|
||||
Loop Until m_Disposed
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Class WisePhilosopher
|
||||
Inherits PhilosopherBase
|
||||
Public Sub New(ByVal name As String, ByVal right As Fork, ByVal left As Fork)
|
||||
MyBase.New(name, right, left)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub MainLoop()
|
||||
Do
|
||||
Console.WriteLine(Name & " sat down")
|
||||
|
||||
Dim first As Fork, second As Fork
|
||||
If m_Left.Number > m_Right.Number Then
|
||||
first = m_Left
|
||||
second = m_Right
|
||||
Else
|
||||
first = m_Right
|
||||
second = m_Left
|
||||
End If
|
||||
|
||||
SyncLock first
|
||||
Console.WriteLine(Name & " picked up fork " & m_Left.Number)
|
||||
|
||||
SyncLock second
|
||||
Console.WriteLine(Name & " picked up fork " & m_Right.Number)
|
||||
|
||||
Console.WriteLine(Name & " ate!!!!")
|
||||
|
||||
Console.WriteLine(Name & " put down fork " & m_Right.Number)
|
||||
End SyncLock
|
||||
|
||||
|
||||
Console.WriteLine(Name & " put down fork " & m_Left.Number)
|
||||
End SyncLock
|
||||
|
||||
Console.WriteLine(Name & " stood up")
|
||||
|
||||
Thread.Sleep(rnd.Next(0, 10000))
|
||||
Loop Until m_Disposed
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
86
Task/Dining-philosophers/Wren/dining-philosophers.wren
Normal file
86
Task/Dining-philosophers/Wren/dining-philosophers.wren
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import "random" for Random
|
||||
import "scheduler" for Scheduler
|
||||
import "timer" for Timer
|
||||
|
||||
var Rand = Random.new()
|
||||
|
||||
var ForkInUse = List.filled(5, false)
|
||||
|
||||
class Fork {
|
||||
construct new(name, index) {
|
||||
_name = name
|
||||
_index = index
|
||||
}
|
||||
|
||||
index { _index }
|
||||
|
||||
pickUp(philosopher) {
|
||||
System.print(" %(philosopher) picked up %(_name)")
|
||||
ForkInUse[index] = true
|
||||
}
|
||||
|
||||
putDown(philosopher) {
|
||||
System.print(" %(philosopher) put down %(_name)")
|
||||
ForkInUse[index] = false
|
||||
}
|
||||
}
|
||||
|
||||
class Philosopher {
|
||||
construct new(pname, f1, f2) {
|
||||
_pname = pname
|
||||
_f1 = f1
|
||||
_f2 = f2
|
||||
}
|
||||
|
||||
delay() { Timer.sleep(Rand.int(300) + 100) }
|
||||
|
||||
eat() {
|
||||
(1..5).each { |bite| // limit to 5 bites say
|
||||
while (true) {
|
||||
System.print("%(_pname) is hungry")
|
||||
if (!ForkInUse[_f1.index] && !ForkInUse[_f2.index]) {
|
||||
_f1.pickUp(_pname)
|
||||
_f2.pickUp(_pname)
|
||||
break
|
||||
}
|
||||
System.print("%(_pname) is unable to pick up both forks")
|
||||
// try again later
|
||||
delay()
|
||||
}
|
||||
System.print("%(_pname) is eating bite %(bite)")
|
||||
// allow time to eat
|
||||
delay()
|
||||
_f2.putDown(_pname)
|
||||
_f1.putDown(_pname)
|
||||
// allow other philospohers time to pick up forks
|
||||
delay()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var diningPhilosophers = Fn.new { |names|
|
||||
var size = names.count
|
||||
var forks = List.filled(size, null)
|
||||
for (i in 0...size) forks[i] = Fork.new("Fork %(i + 1)", i)
|
||||
var philosophers = []
|
||||
var i = 0
|
||||
for (n in names) {
|
||||
var i1 = i
|
||||
var i2 = (i + 1) % size
|
||||
if (i2 < i1) {
|
||||
i1 = i2
|
||||
i2 = i
|
||||
}
|
||||
var p = Philosopher.new(n, forks[i1], forks[i2])
|
||||
philosophers.add(p)
|
||||
i = i + 1
|
||||
}
|
||||
// choose a philosopher at random to start eating
|
||||
var r = Rand.int(size)
|
||||
// schedule the others to eat later
|
||||
for (i in 0...size) if (i != r) Scheduler.add { philosophers[i].eat() }
|
||||
philosophers[r].eat()
|
||||
}
|
||||
|
||||
var names = ["Aristotle", "Kant", "Spinoza", "Marx", "Russell"]
|
||||
diningPhilosophers.call(names)
|
||||
26
Task/Dining-philosophers/Zkl/dining-philosophers-1.zkl
Normal file
26
Task/Dining-philosophers/Zkl/dining-philosophers-1.zkl
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
var [const] forks=(5).pump(List,Atomic.Bool.fp(False)), // True==fork in use
|
||||
seats=(5).pump(List,'wrap(n){ List(forks[n],forks[(n+1)%5]) });
|
||||
fcn sitAndEat(name,n){ // assigned seating
|
||||
while(1){
|
||||
fa,fb:=seats[n].shuffle(); // ambidextrous
|
||||
if(fa.setIf(True,False)){ // got the first fork
|
||||
if(fb.setIf(True,False)){ // got the other fork, nom nom time
|
||||
name.println(" is eating");
|
||||
Atomic.sleep((1).random(5));
|
||||
fa.set(False); fb.set(False); // put forks down
|
||||
return(); // leave the table
|
||||
}
|
||||
else{
|
||||
fa.set(False); // put fork down, try again in a bit
|
||||
name.println(": Could not get two forks");
|
||||
}
|
||||
} else name.println(": Could not get first fork");
|
||||
Atomic.sleep((1).random(2)); // sits for a bit
|
||||
}
|
||||
}
|
||||
fcn philo([(seat,name)]){ // a thread
|
||||
while(1){ // eat and think forever
|
||||
name.println(" is thinking."); Atomic.sleep((1).random(5));
|
||||
sitAndEat(name,seat);
|
||||
}
|
||||
}
|
||||
4
Task/Dining-philosophers/Zkl/dining-philosophers-2.zkl
Normal file
4
Task/Dining-philosophers/Zkl/dining-philosophers-2.zkl
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
T("Aristotle", "Kant", "Spinoza", "Marx", "Russell").enumerate()
|
||||
.apply(philo.launch);
|
||||
|
||||
Atomic.sleep(100000); // hang out in the REPL, aka thread keep alive
|
||||
Loading…
Add table
Add a link
Reference in a new issue