C
#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);
}
C++
#include <vector>
#include <string>
#include <iostream>
#include <boost/cstdint.hpp>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/format.hpp>
#include <boost/shared_ptr.hpp>
typedef boost::mutex Fork;
typedef boost::shared_ptr< Fork > ForkPtr;
typedef boost::lock_guard< Fork > ForkLock;
#define MIN_WAIT_TIME 100
#define NUM_MEALS 10
#define MAX_JITTER 50
template< typename Stream >
class AtomicLogger {
public:
AtomicLogger( Stream& stream ) :
m_mutex(),
m_stream( stream )
{
}
void log( const std::string& str ) {
boost::mutex::scoped_lock lock( m_mutex );
m_stream << str << std::endl;
}
private:
mutable boost::mutex m_mutex;
Stream& m_stream;
};
typedef AtomicLogger< std::ostream > AtomicLoggerOstream;
typedef boost::shared_ptr< AtomicLoggerOstream > AtomicLoggerOstreamPtr;
class Philosopher {
public:
Philosopher(
const std::string& name,
ForkPtr fork_left,
ForkPtr fork_right,
AtomicLoggerOstreamPtr p_logger ) :
m_name( name ),
m_continue( true ),
mp_fork_left( fork_left ),
mp_fork_right( fork_right ),
m_thread( boost::thread( boost::bind( &Philosopher::thread_func,
this,
&m_continue,
mp_fork_left,
mp_fork_right ) ) ),
m_meals_left( NUM_MEALS ),
mp_logger( p_logger )
{
}
~Philosopher() {
done_dining();
wait_for_cmplt();
}
void done_dining() { m_continue = false; }
void wait_for_cmplt() { m_thread.join(); }
private:
inline bool can_grab_fork( ForkPtr& p_fork ) { return p_fork->try_lock(); }
void thread_func( volatile bool* p_continue, ForkPtr fork_left, ForkPtr fork_right ) {
bool failed_to_grab_fork = false;
while( p_continue && m_meals_left ) {
mp_logger->log( boost::str( boost::format( "%1% is thinking" ) % this->m_name ) );
wait();
mp_logger->log( boost::str( boost::format( "%1% is hungry" ) % this->m_name ) );
// attempt to grab forks
if( can_grab_fork( fork_left ) ) {
ForkLock lock_left( *fork_left, boost::adopt_lock );
if( can_grab_fork( fork_right ) ) {
ForkLock lock_right( *fork_right, boost::adopt_lock );
// eating
mp_logger->log( boost::str( boost::format( "%1% is eating (%2%)..." ) % m_name % m_meals_left ) );
wait();
// record the meal
--m_meals_left;
} else {
failed_to_grab_fork = true;
}
} else {
failed_to_grab_fork = true;
}
if( failed_to_grab_fork ) {
mp_logger->log( boost::str( boost::format( "%1% couldn't get forks; waiting..." ) % m_name ) );
failed_to_grab_fork = false;
wait();
}
}
mp_logger->log( boost::str( boost::format( "%1% is done dining" ) % m_name ) );
}
inline void wait() {
wait( MIN_WAIT_TIME + ( std::rand() % MAX_JITTER ) );
}
inline void wait( boost::uint32_t time_in_ms ) {
boost::this_thread::sleep( boost::posix_time::milliseconds( time_in_ms ) );
}
std::string m_name;
volatile bool m_continue;
ForkPtr mp_fork_left; // must be declared before the thread
ForkPtr mp_fork_right; // must be declared before the thread
boost::thread m_thread;
boost::uint32_t m_meals_left;
AtomicLoggerOstreamPtr mp_logger;
};
typedef boost::shared_ptr< Philosopher > PhilosopherPtr;
int main() {
const int N = 5;
std::string names[] = { "Aristotle", "Spinoza", "Russell", "Kant", "Plato" };
std::vector< PhilosopherPtr > philosophers;
philosophers.reserve( N );
// create logger
AtomicLoggerOstreamPtr p_logger( new AtomicLoggerOstream( std::cout ) );
// create forks
std::vector< ForkPtr > forks;
forks.reserve( N );
for( int i = 0; i < N; ++i ) {
forks.push_back( ForkPtr( new Fork() ) );
}
// create philosophers
for( int i = 0; i < N; ++i ) {
philosophers.push_back( PhilosopherPtr(
new Philosopher( names[ i ], forks[ i ], forks[ (i + 1) % N ], p_logger ) ) );
}
// wait for them to finish
for( int i = 0; i < N; ++i ) {
philosophers[ i ]->wait_for_cmplt();
}
p_logger->log( "Everyone is done dining." );
return 0;
}
另一个版本
#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;
}
C#
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 { }
}
Go
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")
}
Java
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);
}
}
Kotlin
// 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)
}
Python
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','Buddha','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()
Ruby
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}