Another update from ingydotnet^djgoku

This commit is contained in:
Ingy döt Net 2015-11-18 06:14:39 +00:00
parent 91df62d461
commit 948b86eafa
7604 changed files with 108452 additions and 22726 deletions

View 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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}
}