Skip to content.

Sections
Personal tools
You are here: Home » ダウンロード » ThreadJack用 » diningPhilosopher

Document Actions
#include <iostream>
#include <stdlib.h>
#include <threadjack.h>

/**
 * 【哲学者の食事】
 *
 * 食堂の丸テーブルに哲学者が5人均等に座っています.
 * テーブルの真ん中にはスパゲッティを盛り付けた大皿があり,
 * 哲学者の前には自分用の小皿があり,自分の両側にはフォークが1つずつ
 * 置いてあります.
 *
 * 哲学者は普段思案に暮れており,お腹が空くと食事をします.
 * 食事をする時は,まず自分の右側にあるフォークを手に取り,次に左側のフォークを
 * 手に取ります.
 * そして,真ん中のスパゲッティを自分の皿に盛り付けた後,左側のフォークを
 * テーブルの元の位置に戻し,右側のフォークで食事をします.
 * 食事が終わったら,右側のフォークをテーブルの元の位置に戻し,また思案に
 * 戻ります.
 * もし,自分の使いたいフォークを別の哲学者が使っていたら,哲学者は紳士なので
 * おとなしくフォークが空くまで待ちます.
 *
 * 通常,哲学者は問題なく行動していますが,ある時全哲学者が同時にお腹が空き,
 * 自分の右側のフォークを取りました.この場合,左側のフォークは別の哲学者が
 * 手にしているので全員がおとなしく左側のフォークが空くのをじっと待ちます.
 *
 * 誰かに
 * 『持ってるフォークを一旦テーブルに置きなさい』
 * と言われるまでは...
 *
 */

///////////////////////////////////////////////////////////////////////////////
// フォーク クラス
class Fork : public TJSyncObject {
public:
    Fork() {
        used = false;  // フォークは未使用
    }

    // フォークを手に取る.
    void take() {
        synchronized(this) {
            if (used == true) {  // フォークは使用中?
                // フォークが戻ってくるまで紳士らしくおとなしく待つ
               wait();
            }
            // フォークが使えるので手に取る
            used = true;
        }
    }

    // フォークを返す.
    void give() {
        synchronized(this) {
            used = false;  // フォークを未使用にする.
            // フォークをおとなしく待ってる紳士に『どうぞ』と言う
           notify();
        }
    }

private:
    bool used;  // フォークの使用/未使用状態
};

//////////////////////////////////////////////////////////////////////////////
// 哲学者 クラス
class Philosopher : public TJThread {
public:
    // コンストラクタ
    Philosopher(int seatNumber, Fork* leftFork, Fork* rightFork) {
        mySeatNumber = seatNumber;  // 私の席はこれか...
        myLeftFork   = leftFork;    // 私の左側のフォークはこれか...
        myRightFork  = rightFork;   // 私の右側のフォークはこれか...
    }

    // 私の思案はこのメソッドから始まる
    virtual void run () {
        // さて私の思案がこれから始まる...
        for (int i=0; i<1000; i++) {
            cout << "Ph." << mySeatNumber << ":number of " << i << endl;

            // 私は思案する
            think();

            // 私は右側のフォークを手に取る
            cout << "Ph." << mySeatNumber << ":getting right fork." << endl;
            myRightFork->take();

            //
            sleep(100);
            //

            // 私は左側のフォークを手に取る
            cout << "Ph." << mySeatNumber << ":getting left fork." << endl;
            myLeftFork->take();

            // 私は両のフォークでスパゲッティを自分の皿に盛る
            cout << "Ph." << mySeatNumber << ":getting spaghetti." << endl;
            // 私は用済みになった左のフォークをテーブルに返す
            cout << "Ph." << mySeatNumber << ":return left fork." << endl;
            myLeftFork->give();

            // 私はスパゲッティを食べる
            cout << "Ph." << mySeatNumber << ":eating spaghetti now.." << endl;
            eat();

            // 私はスパゲッティを食べ終わったので右のフォークをテーブルに返す
            cout << "Ph." << mySeatNumber << ":eat up spaghetti. " << endl;
            cout << "Ph." << mySeatNumber << ":return right fork." << endl;
            myRightFork->give();

            // そして私はまた思案する...
        }
        // 私の思案は1000回の食事と共に終了する
    }

    // 私は思案する.お腹が空くと復帰する.
    void think() const {
        int thinkingTime = rand()%500+100;  // 100~600msecの範囲
        sleep(thinkingTime);
    }

    // 私はスパゲッティを食べる.食べ終わると復帰する.
    void eat() const {
        int eatingTime = rand()%300+100;  // 100msec~400msecの範囲
        sleep(eatingTime);
    }

private:
    int    mySeatNumber;
    Fork*  myLeftFork;
    Fork*  myRightFork;
};

//////////////////////////////////////////////////////////////////////////////
const int NUM = 5;  // 哲学者, フォークの数

int main () {
    Fork*        f[NUM];
    Philosopher* p[NUM];

    // フォークオブジェクトの生成
    for (int i=0; i<NUM; i++) {
        f[i] = new Fork;
    }

    // 哲学者オブジェクトの生成
    for (int i=0; i<NUM; i++) {
        p[i] = new Philosopher(i, f[i%NUM], f[(i+1)%NUM]);
    }

    // 哲学者の思案開始
    for (int i=0; i<NUM; i++) {
        p[i]->start();
    }

    // 哲学者の思案終了待ち
    for (int i=0; i<NUM; i++) {
        p[i]->join();
    }

    // 後始末
    for (int i=0; i<NUM; i++) {
        delete f[i];
    }

    return 0;
}