Another update from ingydotnet^djgoku
This commit is contained in:
parent
91df62d461
commit
948b86eafa
7604 changed files with 108452 additions and 22726 deletions
129
Task/Dining-philosophers/C++/dining-philosophers-2.cpp
Normal file
129
Task/Dining-philosophers/C++/dining-philosophers-2.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
//We are using only standard library, so snprintf instead of Boost::Format
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
std::mutex cout_mutex;
|
||||
|
||||
struct Fork {
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
struct Dinner {
|
||||
std::atomic<bool> ready {false};
|
||||
std::array<Fork, 5> forks;
|
||||
~Dinner() { std::cout << "Dinner is over"; }
|
||||
};
|
||||
|
||||
class Philosopher
|
||||
{
|
||||
std::mt19937 rng{std::random_device {}()};
|
||||
|
||||
const std::string name;
|
||||
const Dinner& dinner;
|
||||
Fork& left;
|
||||
Fork& right;
|
||||
std::thread worker;
|
||||
|
||||
void live();
|
||||
void dine();
|
||||
void ponder();
|
||||
public:
|
||||
Philosopher(std::string name_, const Dinner& dinn, Fork& l, Fork& r)
|
||||
: name(std::move(name_)), dinner(dinn) , left(l), right(r), worker(&Philosopher::live, this)
|
||||
{}
|
||||
~Philosopher()
|
||||
{
|
||||
worker.join();
|
||||
std::lock_guard<std::mutex> cout_lock(cout_mutex);
|
||||
std::cout << name << " went to sleep." << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
void Philosopher::live()
|
||||
{
|
||||
while (not dinner.ready)
|
||||
; //You spin me right round, baby, right round...
|
||||
do {//Aquire forks first
|
||||
//lock uses deadlock prevention mechanism to acquire mutexes safely
|
||||
std::lock(left.mutex, right.mutex);
|
||||
dine(); //Dine adopts lock on forks and releases them
|
||||
if(not dinner.ready) break;
|
||||
ponder();
|
||||
} while(dinner.ready);
|
||||
}
|
||||
|
||||
void Philosopher::dine()
|
||||
{
|
||||
std::lock_guard<std::mutex> left_lock( left.mutex, std::adopt_lock);
|
||||
std::lock_guard<std::mutex> right_lock(right.mutex, std::adopt_lock);
|
||||
|
||||
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);
|
||||
|
||||
if(not dinner.ready) return;
|
||||
{
|
||||
std::lock_guard<std::mutex> cout_lock(cout_mutex);
|
||||
std::cout << name << " started eating." << std::endl;
|
||||
}
|
||||
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)*50));
|
||||
snprintf(buffer, buf_size, reactions[i], foods[i]);
|
||||
std::lock_guard<std::mutex> cout_lock(cout_mutex);
|
||||
std::cout << name << ": " << buffer << std::endl;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng))*50);
|
||||
std::lock_guard<std::mutex> cout_lock(cout_mutex);
|
||||
std::cout << name << " finished and left." << std::endl;
|
||||
}
|
||||
|
||||
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)*150));
|
||||
std::lock_guard<std::mutex> cout_lock(cout_mutex);
|
||||
std::cout << name << " is pondering about " << topics[dist(rng)] << '.' << std::endl;
|
||||
if(not dinner.ready) return;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(wait(rng)*150));
|
||||
std::lock_guard<std::mutex> cout_lock(cout_mutex);
|
||||
std::cout << name << " is hungry again!" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Dinner dinner;
|
||||
std::array<Philosopher, 5> philosophers {{
|
||||
{"Aristotle", dinner, dinner.forks[0], dinner.forks[1]},
|
||||
{"Kant", dinner, dinner.forks[1], dinner.forks[2]},
|
||||
{"Spinoza", dinner, dinner.forks[2], dinner.forks[3]},
|
||||
{"Marx", dinner, dinner.forks[3], dinner.forks[4]},
|
||||
{"Russell", dinner, dinner.forks[4], dinner.forks[0]},
|
||||
}};
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
std::cout << "Dinner started!" << std::endl;
|
||||
dinner.ready = true;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
dinner.ready = false;
|
||||
std::lock_guard<std::mutex> cout_lock(cout_mutex);
|
||||
std::cout << "It is dark outside..." << std::endl;
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
class Fork {
|
||||
has $!lock = Lock.new;
|
||||
method grab($who, $which) {
|
||||
remark "$who grabbing $which fork";
|
||||
say "$who grabbing $which fork";
|
||||
$!lock.lock;
|
||||
}
|
||||
method drop($who, $which) {
|
||||
remark "$who dropping $which fork";
|
||||
say "$who dropping $which fork";
|
||||
$!lock.unlock;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,10 +16,6 @@ class Lollipop {
|
|||
method yours { $!channel.receive }
|
||||
}
|
||||
|
||||
my $out = Channel.new;
|
||||
sub remark($msg) { $out.send($msg) }
|
||||
start { loop { $out.receive.say } }
|
||||
|
||||
sub dally($sec) { sleep 0.01 + rand * $sec }
|
||||
|
||||
sub MAIN(*@names) {
|
||||
|
|
@ -31,25 +27,25 @@ sub MAIN(*@names) {
|
|||
my $lollipop = Lollipop.new;
|
||||
start { $lollipop.yours; }
|
||||
|
||||
my @philosophers = do for @names Z @lfork Z @rfork -> $n, $l, $r {
|
||||
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');
|
||||
remark "$n eating";
|
||||
say "$n eating";
|
||||
dally 10;
|
||||
$l.drop($n,'left');
|
||||
$r.drop($n,'right');
|
||||
|
||||
$lollipop.mine($n);
|
||||
sleep 1; # lick at least once
|
||||
remark "$n lost lollipop to $lollipop.yours(), now digesting";
|
||||
say "$n lost lollipop to $lollipop.yours(), now digesting";
|
||||
|
||||
dally 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
await @philosophers;
|
||||
sink await @philosophers;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,48 @@
|
|||
/*REXX prm demonstrates a solution to solve dining philosophers problem.*/
|
||||
parse arg seed diners /*get optional arguments from CL.*/
|
||||
if seed\=='' & seed\==',' then call random ,, seed /*for repeatability*/
|
||||
if diners='' then diners='Aristotle,Kant,Spinoza,Marx,Russell'
|
||||
tell=left(seed,1)\=='+' /*Leading + in SEED? No stats.*/
|
||||
diners=translate(diners,,',') /*change a commatized diners list*/
|
||||
#=words(diners); @.=0 /*the number of dining philospers*/
|
||||
eatL=15; eatH= 60 /*min & max minutes for eating. */
|
||||
thinkL=30; thinkH=180 /* " " " " " thinking.*/
|
||||
forks.=1 /*indicate all forks are on table*/
|
||||
do tic=1 /*use minutes as time advancement*/
|
||||
call grabForks /*see if anybody can grab 2 forks*/
|
||||
call passTime /*handle diners eating | thinking*/
|
||||
end /*tic*/ /* ··· and time marches on ··· */
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────FORK subroutine─────────────────────*/
|
||||
fork: parse arg x 1 ox; x=abs(x); L=x-1; if L==0 then L=# /*boundry ? */
|
||||
if ox<0 then do; forks.L=1; forks.x=1; return; end /*drop forks*/
|
||||
got2=forks.L & forks.x /*did we get two forks or not? */
|
||||
if got2 then do; forks.L=0; forks.x=0; end /*got forks.*/
|
||||
return got2 /*return with success or failure.*/
|
||||
/*──────────────────────────────────GRABFORKS subroutine────────────────*/
|
||||
grabForks: do person=1 for # /*see if any person can grab two.*/
|
||||
if @.person.status\==0 then iterate /*diner ain't waiting*/
|
||||
if \fork(person) then iterate /*diner didn't grab 2*/
|
||||
@.person.status='eating' /*diner now chomps on spaghetti. */
|
||||
@.person.dur=random(eatL,eatH) /*how long will diner eat? */
|
||||
end /*person*/
|
||||
/*REXX pgm 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 /*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 subroutine───────────────────────────*/
|
||||
fork: parse arg x 1 ox; x=abs(x); L=x-1; if L==0 then L=# /*on a boundary? */
|
||||
if ox<0 then do; forks.L=1; forks.x=1; return; end /*drop the forks.*/
|
||||
got2=forks.L & forks.x /*get 2 forks │ ¬*/
|
||||
if got2 then do; forks.L=0; forks.x=0; end /*got two forks. */
|
||||
return got2 /*return with success ··· or failure. */
|
||||
/*──────────────────────────────────GRABFORKS subroutine──────────────────────*/
|
||||
grabForks: do person=1 for # /*see if any person can grab two forks.*/
|
||||
if @.person.state\==0 then iterate /*the diner ain't waiting. */
|
||||
if \fork(person) then iterate /*the diner didn't grab 2. */
|
||||
@.person.state= 'eating' /*diner spaghetti slurping.*/
|
||||
@.person.dur=random(eatL,eatH) /*how long will diner eat? */
|
||||
end /*person*/ /* [↑] handle all diners. */
|
||||
return
|
||||
/*──────────────────────────────────PASSTIME subroutine─────────────────*/
|
||||
passTime: if tell then say /*show a (blank line) separator. */
|
||||
do p=1 for # /*process each diner's activity. */
|
||||
if tell then say right(tic,9,'.') right(word(diners,p),20),
|
||||
right(word(@.p.status 'waiting',1+(@.p.status==0)),9) right(@.p.dur,5)
|
||||
if @.p.dur==0 then iterate /*diner is waiting for two forks.*/
|
||||
@.p.dur=@.p.dur-1 /*indicate 1 timeUnit has gone by*/
|
||||
if @.p.dur\==0 then iterate /*Activity done? No, keep it up.*/
|
||||
select /*handle the activity being done.*/
|
||||
when @.p.status=='eating' then do /*now, leave the table.*/
|
||||
call fork -p /*drop the forks.*/
|
||||
@.p.status='thinking' /*status.*/
|
||||
@.p.dur=random(thinkL,thinkH)
|
||||
end
|
||||
when @.p.status=='thinking' then @.p.status=0 /*──► table*/
|
||||
otherwise nop /*diner must be waiting on forks.*/
|
||||
end /*select*/
|
||||
end /*p*/
|
||||
/*──────────────────────────────────PASSTIME subroutine───────────────────────*/
|
||||
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 /* [↓] diner ──► the table.*/
|
||||
else if @.p.state=='thinking' then @.p.state=0
|
||||
end /*p*/ /*[↑] P (person) ≡dining philosophers.*/
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,99 +1,63 @@
|
|||
extern mod extra;
|
||||
use std::rt::io::timer;
|
||||
use extra::comm::DuplexStream;
|
||||
use std::thread;
|
||||
use std::sync::{Mutex, Arc};
|
||||
|
||||
fn phil(phil: ~str, diner: &DuplexStream<int, int>, firstChopstick: int, secondChopstick: int)
|
||||
{
|
||||
let mut sleep_time: u64;
|
||||
print(fmt!("%s sat down\n", phil));
|
||||
for _ in range(1,3)
|
||||
{
|
||||
print(fmt!("%s is thinking\n", phil));
|
||||
sleep_time = std::rand::random();
|
||||
timer::sleep((sleep_time%5)*500);
|
||||
print(fmt!("%s is hungry\n", phil));
|
||||
//get left chopstick
|
||||
diner.send(firstChopstick);
|
||||
let mut recv: int = diner.recv();
|
||||
while recv == 0
|
||||
{
|
||||
diner.send(firstChopstick);
|
||||
recv = diner.recv();
|
||||
}
|
||||
print(fmt!("%s picked up his left chopstick\n", phil));
|
||||
//get right chopstick
|
||||
diner.send(secondChopstick);
|
||||
recv = diner.recv();
|
||||
while recv == 0
|
||||
{
|
||||
diner.send(secondChopstick);
|
||||
recv = diner.recv();
|
||||
}
|
||||
print(fmt!("%s picked up his right chopstick\n", phil));
|
||||
//eat
|
||||
print(fmt!("%s is eating...\n", phil));
|
||||
sleep_time = std::rand::random();
|
||||
timer::sleep((sleep_time%3)*500);
|
||||
print(fmt!("%s is done eating\n", phil));
|
||||
//set down left chopstick
|
||||
print(fmt!("%s set down his left chopstick\n", phil));
|
||||
diner.send(-1*firstChopstick);
|
||||
//set down right chopstick
|
||||
print(fmt!("%s set down his right chopstick\n", phil));
|
||||
diner.send(-1*secondChopstick);
|
||||
|
||||
}
|
||||
diner.send(0);
|
||||
diner.recv();
|
||||
print(fmt!("%s has exited\n", phil));
|
||||
struct Philosopher {
|
||||
name: String,
|
||||
left: usize,
|
||||
right: usize,
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
//set the table:
|
||||
//false means chopstick is on the table
|
||||
//true means chopstick is taken
|
||||
let mut chopsticks: ~[bool] = ~[false, false, false, false, false];
|
||||
|
||||
//diner_ will try to take resources from the table, host_
|
||||
//will respond with whether that action was successful.
|
||||
let (diner1, host1) = DuplexStream();
|
||||
let (diner2, host2) = DuplexStream();
|
||||
let (diner3, host3) = DuplexStream();
|
||||
let (diner4, host4) = DuplexStream();
|
||||
let (diner5, host5) = DuplexStream();
|
||||
|
||||
//Make the first 4 "right-handed" philosophers
|
||||
do spawn{ phil(~"Hobbes", &diner1, 1, 2); }
|
||||
do spawn{ phil(~"Locke", &diner2, 2, 3); }
|
||||
do spawn{ phil(~"Machiavelli", &diner3, 3, 4); }
|
||||
do spawn{ phil(~"Montesquieu", &diner4, 4, 5); }
|
||||
//Make the last, "left-handed" philosopher
|
||||
do spawn{ phil(~"Rousseau", &diner5, 1, 5); }
|
||||
|
||||
//keep track of number of people still at the table
|
||||
let mut remaining = 5;
|
||||
while remaining > 0
|
||||
{
|
||||
matchReq(&mut chopsticks, &host1, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host2, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host3, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host4, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host5, &mut remaining);
|
||||
std::task::deschedule();
|
||||
}
|
||||
}
|
||||
|
||||
fn matchReq(chopsticks: &mut ~[bool], host: &DuplexStream<int, int>, remaining: &mut int) {
|
||||
if (host.peek())
|
||||
{
|
||||
let from = host.try_recv();
|
||||
match from
|
||||
{
|
||||
Some(0) => { *remaining += -1; host.try_send(0); return; },
|
||||
Some(x) if x > 0 => { if(chopsticks[x-1]) { host.send(0); } else { chopsticks[x-1] = true; host.send(1); } },
|
||||
Some(x) => { chopsticks[(-x)-1] = false; },
|
||||
None => { *remaining += -1; host.try_send(0); return; }
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue