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