00001 // Filename: test_diners.cxx 00002 // Created by: cary (16Sep98) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 // A solution to the famous dining philosophers, implemented using the 00020 // threading abstraction. This program exercises thread creation and 00021 // destruction, mutexes, and condition variables. 00022 00023 #include "pandabase.h" 00024 #include "thread.h" 00025 #include "conditionVar.h" 00026 #include "mutexHolder.h" 00027 #include "pointerTo.h" 00028 00029 #ifdef WIN32_VC 00030 static int last_rand = 0; 00031 #endif /* __WIN32__ */ 00032 00033 Mutex rand_mutex; 00034 00035 static double random_f(double max) 00036 { 00037 MutexHolder l(rand_mutex); 00038 int i = rand(); 00039 #ifdef WIN32_VC 00040 last_rand = i; 00041 #endif /* __WIN32__ */ 00042 return max * (double)i / (double)RAND_MAX; 00043 } 00044 00045 Mutex print_mutex; 00046 00047 #define PRINTMSG(x) { MutexHolder l(print_mutex); x; } 00048 00049 // n philosophers sharing n chopsticks. Philosophers are poor folk and can't 00050 // afford luxuries like 2 chopsticks per person. 00051 #define N_DINERS 5 00052 00053 Mutex chopsticks[N_DINERS]; 00054 00055 // At most n philosophers are allowed into the room, others would have to 00056 // wait at the door. This restriction demonstrates the use of condition 00057 // variables. 00058 00059 Mutex room_mutex; 00060 00061 ConditionVar room_condition(room_mutex); 00062 int room_occupancy = 0; 00063 00064 class philosopher; 00065 PT(philosopher) phils[N_DINERS]; 00066 00067 class philosopher : public Thread { 00068 private: 00069 int _id; 00070 void thread_main() { 00071 #ifdef WIN32_VC 00072 rand_mutex.lock(); 00073 srand(last_rand); 00074 rand_mutex.release(); 00075 #endif /* __WIN32__ */ 00076 int l = _id; 00077 int r = l+1; 00078 if (r == N_DINERS) 00079 r = 0; 00080 if (l & 1) { 00081 int t = l; 00082 l = r; 00083 r = t; 00084 } 00085 PRINTMSG(cerr << "Philosopher #" << _id << " has entered the room." 00086 << endl); 00087 int count = (int)random_f(10.0) + 1; 00088 while (--count) { 00089 chopsticks[l].lock(); 00090 chopsticks[r].lock(); 00091 PRINTMSG(cerr << "Philosopher #" << _id 00092 << " is eating spaghetti now." << endl); 00093 Thread::sleep(random_f(3.0)); 00094 chopsticks[l].release(); 00095 chopsticks[r].release(); 00096 PRINTMSG(cerr << "Philosopher #" << _id 00097 << " is pondering about life." << endl); 00098 Thread::sleep(random_f(3.0)); 00099 } 00100 room_mutex.lock(); 00101 --room_occupancy; 00102 phils[_id] = (philosopher*)0L; 00103 room_condition.signal(); 00104 room_mutex.release(); 00105 PRINTMSG(cerr << "Philosopher #" << _id << " has left the room (" 00106 << room_occupancy << " left)." << endl); 00107 } 00108 00109 inline void* make_arg(const int i) { return (void*)new int(i); } 00110 public: 00111 philosopher(const int id) : Thread("philosopher") { 00112 _id = id; 00113 } 00114 }; 00115 00116 int main(int, char**) 00117 { 00118 int i; 00119 room_mutex.lock(); 00120 for (i=0; i<N_DINERS; ++i) { 00121 phils[i] = new philosopher(i); 00122 phils[i]->start(TP_normal, false, false); 00123 } 00124 room_occupancy = N_DINERS; 00125 while (1) { 00126 while (room_occupancy == N_DINERS) { 00127 PRINTMSG(cerr << "main thread about to block " << room_occupancy 00128 << endl); 00129 room_condition.wait(); 00130 } 00131 // hmm.. someone left the room. 00132 room_mutex.release(); 00133 // sleep for a while and then create a new philosopher 00134 PRINTMSG(cerr << "main thread sleep" << endl); 00135 Thread::sleep(2.0); 00136 PRINTMSG(cerr << "main thread wake up" << endl); 00137 room_mutex.lock(); 00138 for (i=0; i<N_DINERS; ++i) 00139 if (phils[i] == (philosopher*)0L) 00140 break; 00141 if (i == N_DINERS) { 00142 PRINTMSG(cerr 00143 << "Contrary to what I was tolk, no one has left the room!!!" 00144 << endl); 00145 PRINTMSG(cerr << "I give up!" << endl); 00146 Thread::prepare_for_exit(); 00147 exit(1); 00148 } 00149 phils[i] = new philosopher(i); 00150 ++room_occupancy; 00151 } 00152 }