哲学家用餐问题(Dining philosophers)【代码实现】

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}
发布了56 篇原创文章 · 获赞 166 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_36721220/article/details/98673576
今日推荐