Dining Philosophers Problem (DPP) example for the QP active object framework. Demonstrates: event-driven programming, hierarchical state machines in C++, modeling and graphical state machine design, code generation, preemptive multitasking, software tracing, power saving mode, direct event posting, publish-subscribe. More information available in the [[/users/QL/notebook|Quantum Leaps Notebook pages]]. See also [[http://www.state-machine.com|state-machine.com]].
philo.cpp
00001 ////////////////////////////////////////////////////////////////////////////// 00002 // Model: dpp.qm 00003 // File: ././philo.cpp 00004 // 00005 // This file has been generated automatically by QP Modeler (QM). 00006 // DO NOT EDIT THIS FILE MANUALLY. 00007 // 00008 // Please visit www.state-machine.com/qm for more information. 00009 ////////////////////////////////////////////////////////////////////////////// 00010 #include "qp_port.h" 00011 #include "dpp.h" 00012 #include "bsp.h" 00013 00014 namespace DPP { 00015 00016 Q_DEFINE_THIS_FILE 00017 00018 // Active object class ------------------------------------------------------- 00019 // @(/2/0) ................................................................... 00020 class Philo : public QP::QActive { 00021 private: 00022 QP::QTimeEvt m_timeEvt; 00023 00024 public: 00025 Philo(); 00026 00027 protected: 00028 static QP::QState initial(Philo * const me, QP::QEvt const * const e); 00029 static QP::QState thinking(Philo * const me, QP::QEvt const * const e); 00030 static QP::QState hungry(Philo * const me, QP::QEvt const * const e); 00031 static QP::QState eating(Philo * const me, QP::QEvt const * const e); 00032 }; 00033 00034 // Local objects ------------------------------------------------------------- 00035 static Philo l_philo[N_PHILO]; // storage for all Philos 00036 00037 // helper function to provide a randomized think time for Philos 00038 inline QP::QTimeEvtCtr think_time() { 00039 return static_cast<QP::QTimeEvtCtr>((BSP_random() % BSP_TICKS_PER_SEC) 00040 + (BSP_TICKS_PER_SEC/2U)); 00041 } 00042 00043 // helper function to provide a randomized eat time for Philos 00044 inline QP::QTimeEvtCtr eat_time() { 00045 return static_cast<QP::QTimeEvtCtr>((BSP_random() % BSP_TICKS_PER_SEC) 00046 + BSP_TICKS_PER_SEC); 00047 } 00048 00049 // helper function to provide the ID of Philo "me" 00050 inline uint8_t PHILO_ID(Philo const * const me) { 00051 return static_cast<uint8_t>(me - l_philo); 00052 } 00053 00054 enum InternalSignals { // internal signals 00055 TIMEOUT_SIG = MAX_SIG 00056 }; 00057 00058 // Global objects ------------------------------------------------------------ 00059 QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO 00060 &l_philo[0], 00061 &l_philo[1], 00062 &l_philo[2], 00063 &l_philo[3], 00064 &l_philo[4] 00065 }; 00066 00067 // Philo definition ---------------------------------------------------------- 00068 // @(/2/0) ................................................................... 00069 // @(/2/0/1) ................................................................. 00070 Philo::Philo() 00071 : QActive(Q_STATE_CAST(&Philo::initial)), 00072 m_timeEvt(TIMEOUT_SIG) 00073 { 00074 } 00075 00076 // @(/2/0/2) ................................................................. 00077 // @(/2/0/2/0) 00078 QP::QState Philo::initial(Philo * const me, QP::QEvt const * const e) { 00079 static bool registered = false; // starts off with 0, per C-standard 00080 (void)e; // suppress the compiler warning about unused parameter 00081 if (!registered) { 00082 registered = true; 00083 00084 QS_OBJ_DICTIONARY(&l_philo[0]); 00085 QS_OBJ_DICTIONARY(&l_philo[0].m_timeEvt); 00086 QS_OBJ_DICTIONARY(&l_philo[1]); 00087 QS_OBJ_DICTIONARY(&l_philo[1].m_timeEvt); 00088 QS_OBJ_DICTIONARY(&l_philo[2]); 00089 QS_OBJ_DICTIONARY(&l_philo[2].m_timeEvt); 00090 QS_OBJ_DICTIONARY(&l_philo[3]); 00091 QS_OBJ_DICTIONARY(&l_philo[3].m_timeEvt); 00092 QS_OBJ_DICTIONARY(&l_philo[4]); 00093 QS_OBJ_DICTIONARY(&l_philo[4].m_timeEvt); 00094 00095 QS_FUN_DICTIONARY(&Philo::initial); 00096 QS_FUN_DICTIONARY(&Philo::thinking); 00097 QS_FUN_DICTIONARY(&Philo::hungry); 00098 QS_FUN_DICTIONARY(&Philo::eating); 00099 } 00100 QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal for each Philos 00101 QS_SIG_DICTIONARY(TIMEOUT_SIG, me); // signal for each Philos 00102 00103 me->subscribe(EAT_SIG); 00104 return Q_TRAN(&Philo::thinking); 00105 } 00106 // @(/2/0/2/1) ............................................................... 00107 QP::QState Philo::thinking(Philo * const me, QP::QEvt const * const e) { 00108 QP::QState status; 00109 switch (e->sig) { 00110 // @(/2/0/2/1) 00111 case Q_ENTRY_SIG: { 00112 me->m_timeEvt.postIn(me, think_time()); 00113 status = Q_HANDLED(); 00114 break; 00115 } 00116 // @(/2/0/2/1) 00117 case Q_EXIT_SIG: { 00118 (void)me->m_timeEvt.disarm(); 00119 status = Q_HANDLED(); 00120 break; 00121 } 00122 // @(/2/0/2/1/0) 00123 case TIMEOUT_SIG: { 00124 status = Q_TRAN(&Philo::hungry); 00125 break; 00126 } 00127 // @(/2/0/2/1/1) 00128 case EAT_SIG: // intentionally fall through 00129 case DONE_SIG: { 00130 /* EAT or DONE must be for other Philos than this one */ 00131 Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me)); 00132 status = Q_HANDLED(); 00133 break; 00134 } 00135 default: { 00136 status = Q_SUPER(&QHsm::top); 00137 break; 00138 } 00139 } 00140 return status; 00141 } 00142 // @(/2/0/2/2) ............................................................... 00143 QP::QState Philo::hungry(Philo * const me, QP::QEvt const * const e) { 00144 QP::QState status; 00145 switch (e->sig) { 00146 // @(/2/0/2/2) 00147 case Q_ENTRY_SIG: { 00148 TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG); 00149 pe->philoNum = PHILO_ID(me); 00150 AO_Table->POST(pe, me); 00151 status = Q_HANDLED(); 00152 break; 00153 } 00154 // @(/2/0/2/2/0) 00155 case EAT_SIG: { 00156 // @(/2/0/2/2/0/0) 00157 if (Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(me)) { 00158 status = Q_TRAN(&Philo::eating); 00159 } 00160 else { 00161 status = Q_UNHANDLED(); 00162 } 00163 break; 00164 } 00165 // @(/2/0/2/2/1) 00166 case DONE_SIG: { 00167 /* DONE must be for other Philos than this one */ 00168 Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me)); 00169 status = Q_HANDLED(); 00170 break; 00171 } 00172 default: { 00173 status = Q_SUPER(&QHsm::top); 00174 break; 00175 } 00176 } 00177 return status; 00178 } 00179 // @(/2/0/2/3) ............................................................... 00180 QP::QState Philo::eating(Philo * const me, QP::QEvt const * const e) { 00181 QP::QState status; 00182 switch (e->sig) { 00183 // @(/2/0/2/3) 00184 case Q_ENTRY_SIG: { 00185 me->m_timeEvt.postIn(me, eat_time()); 00186 status = Q_HANDLED(); 00187 break; 00188 } 00189 // @(/2/0/2/3) 00190 case Q_EXIT_SIG: { 00191 TableEvt *pe = Q_NEW(TableEvt, DONE_SIG); 00192 pe->philoNum = PHILO_ID(me); 00193 QP::QF::PUBLISH(pe, me); 00194 (void)me->m_timeEvt.disarm(); 00195 status = Q_HANDLED(); 00196 break; 00197 } 00198 // @(/2/0/2/3/0) 00199 case TIMEOUT_SIG: { 00200 status = Q_TRAN(&Philo::thinking); 00201 break; 00202 } 00203 // @(/2/0/2/3/1) 00204 case EAT_SIG: // intentionally fall through 00205 case DONE_SIG: { 00206 /* EAT or DONE must be for other Philos than this one */ 00207 Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me)); 00208 status = Q_HANDLED(); 00209 break; 00210 } 00211 default: { 00212 status = Q_SUPER(&QHsm::top); 00213 break; 00214 } 00215 } 00216 return status; 00217 } 00218 00219 00220 } // namespace DPP
Generated on Sat Jul 23 2022 13:10:38 by 1.7.2