Dining Philosopher Problem example with MSM state machines : QMActive(Q_STATE_CAST(&Philo::initial)), m_timeEvt(this, TIMEOUT_SIG, 0U) static bool registered = false; // starts off with 0, per C-standard (void)e; // suppress the compiler warning about unused parameter if (!registered) { registered = true; QS_OBJ_DICTIONARY(&l_philo[0]); QS_OBJ_DICTIONARY(&l_philo[0].m_timeEvt); QS_OBJ_DICTIONARY(&l_philo[1]); QS_OBJ_DICTIONARY(&l_philo[1].m_timeEvt); QS_OBJ_DICTIONARY(&l_philo[2]); QS_OBJ_DICTIONARY(&l_philo[2].m_timeEvt); QS_OBJ_DICTIONARY(&l_philo[3]); QS_OBJ_DICTIONARY(&l_philo[3].m_timeEvt); QS_OBJ_DICTIONARY(&l_philo[4]); QS_OBJ_DICTIONARY(&l_philo[4].m_timeEvt); QS_FUN_DICTIONARY(&Philo::initial); QS_FUN_DICTIONARY(&Philo::thinking); QS_FUN_DICTIONARY(&Philo::hungry); QS_FUN_DICTIONARY(&Philo::eating); } QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal for each Philos QS_SIG_DICTIONARY(TIMEOUT_SIG, me); // signal for each Philos me->subscribe(EAT_SIG); me->m_timeEvt.armX(think_time(), 0U); (void)me->m_timeEvt.disarm(); /* EAT or DONE must be for other Philos than this one */ Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me)); TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG); pe->philoNum = PHILO_ID(me); AO_Table->POST(pe, me); Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(me) /* DONE must be for other Philos than this one */ Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me)); me->m_timeEvt.armX(eat_time(), 0U); TableEvt *pe = Q_NEW(TableEvt, DONE_SIG); pe->philoNum = PHILO_ID(me); QP::QF::PUBLISH(pe, me); (void)me->m_timeEvt.disarm(); /* EAT or DONE must be for other Philos than this one */ Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(me)); : QMActive(Q_STATE_CAST(&Table::initial)) for (uint8_t n = 0U; n < N_PHILO; ++n) { m_fork[n] = FREE; m_isHungry[n] = false; } (void)e; // suppress the compiler warning about unused parameter QS_OBJ_DICTIONARY(&l_table); QS_FUN_DICTIONARY(&QP::QHsm::top); QS_FUN_DICTIONARY(&Table::initial); QS_FUN_DICTIONARY(&Table::active); QS_FUN_DICTIONARY(&Table::serving); QS_FUN_DICTIONARY(&Table::paused); QS_SIG_DICTIONARY(DONE_SIG, (void *)0); // global signals QS_SIG_DICTIONARY(EAT_SIG, (void *)0); QS_SIG_DICTIONARY(PAUSE_SIG, (void *)0); QS_SIG_DICTIONARY(SERVE_SIG, (void *)0); QS_SIG_DICTIONARY(TERMINATE_SIG, (void *)0); QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal just for Table me->subscribe(DONE_SIG); me->subscribe(PAUSE_SIG); me->subscribe(SERVE_SIG); me->subscribe(TERMINATE_SIG); for (uint8_t n = 0U; n < N_PHILO; ++n) { me->m_fork[n] = FREE; me->m_isHungry[n] = false; BSP::displayPhilStat(n, THINKING); } BSP::terminate(0); Q_ERROR(); for (uint8_t n = 0U; n < N_PHILO; ++n) { // give permissions to eat... if (me->m_isHungry[n] && (me->m_fork[LEFT(n)] == FREE) && (me->m_fork[n] == FREE)) { me->m_fork[LEFT(n)] = USED; me->m_fork[n] = USED; TableEvt *te = Q_NEW(TableEvt, EAT_SIG); te->philoNum = n; QP::QF::PUBLISH(te, me); me->m_isHungry[n] = false; BSP::displayPhilStat(n, EATING); } } uint8_t n = Q_EVT_CAST(TableEvt)->philoNum; // phil ID must be in range and he must be not hungry Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n])); BSP::displayPhilStat(n, HUNGRY); uint8_t m = LEFT(n); (me->m_fork[m] == FREE) && (me->m_fork[n] == FREE) me->m_fork[m] = USED; me->m_fork[n] = USED; TableEvt *pe = Q_NEW(TableEvt, EAT_SIG); pe->philoNum = n; QP::QF::PUBLISH(pe, me); BSP::displayPhilStat(n, EATING); else me->m_isHungry[n] = true; uint8_t n = Q_EVT_CAST(TableEvt)->philoNum; // phil ID must be in range and he must be not hungry Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n])); BSP::displayPhilStat(n, THINKING); uint8_t m = LEFT(n); // both forks of Phil[n] must be used Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED)); me->m_fork[m] = FREE; me->m_fork[n] = FREE; m = RIGHT(n); // check the right neighbor if (me->m_isHungry[m] && (me->m_fork[m] == FREE)) { me->m_fork[n] = USED; me->m_fork[m] = USED; me->m_isHungry[m] = false; TableEvt *pe = Q_NEW(TableEvt, EAT_SIG); pe->philoNum = m; QP::QF::PUBLISH(pe, me); BSP::displayPhilStat(m, EATING); } m = LEFT(n); // check the left neighbor n = LEFT(m); // left fork of the left neighbor if (me->m_isHungry[m] && (me->m_fork[n] == FREE)) { me->m_fork[m] = USED; me->m_fork[n] = USED; me->m_isHungry[m] = false; TableEvt *pe = Q_NEW(TableEvt, EAT_SIG); pe->philoNum = m; QP::QF::PUBLISH(pe, me); BSP::displayPhilStat(m, EATING); } Q_ERROR(); BSP::displayPaused(1U); BSP::displayPaused(0U); uint8_t n = Q_EVT_CAST(TableEvt)->philoNum; // philo ID must be in range and he must be not hungry Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n])); me->m_isHungry[n] = true; BSP::displayPhilStat(n, HUNGRY); uint8_t n = Q_EVT_CAST(TableEvt)->philoNum; // phil ID must be in range and he must be not hungry Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n])); BSP::displayPhilStat(n, THINKING); uint8_t m = LEFT(n); /* both forks of Phil[n] must be used */ Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED)); me->m_fork[m] = FREE; me->m_fork[n] = FREE; #ifndef dpp_h #define dpp_h namespace DPP { enum DPPSignals { EAT_SIG = QP::Q_USER_SIG, // published by Table to let a philosopher eat DONE_SIG, // published by Philosopher when done eating PAUSE_SIG, // published by BSP to pause the application SERVE_SIG, // published by BSP to serve re-start serving forks TERMINATE_SIG, // published by BSP to terminate the application MAX_PUB_SIG, // the last published signal HUNGRY_SIG, // posted direclty to Table from hungry Philo MAX_SIG // the last signal }; } // namespace DPP $declare(Events::TableEvt) // number of philosophers #define N_PHILO ((uint8_t)5) $declare(AOs::AO_Philo[N_PHILO]) $declare(AOs::AO_Table) #ifdef qxk_h $declare(AOs::XT_Test) #endif // qxk_h #endif // dpp_h #include "qpcpp.h" #include "dpp.h" #include "bsp.h" Q_DEFINE_THIS_FILE // Active object class ------------------------------------------------------- $declare(AOs::Philo) namespace DPP { // Local objects ------------------------------------------------------------- static Philo l_philo[N_PHILO]; // storage for all Philos // helper function to provide a randomized think time for Philos inline QP::QTimeEvtCtr think_time() { return static_cast<QP::QTimeEvtCtr>((BSP::random() % BSP::TICKS_PER_SEC) + (BSP::TICKS_PER_SEC/2U)); } // helper function to provide a randomized eat time for Philos inline QP::QTimeEvtCtr eat_time() { return static_cast<QP::QTimeEvtCtr>((BSP::random() % BSP::TICKS_PER_SEC) + BSP::TICKS_PER_SEC); } // helper function to provide the ID of Philo "me" inline uint8_t PHILO_ID(Philo const * const me) { return static_cast<uint8_t>(me - l_philo); } enum InternalSignals { // internal signals TIMEOUT_SIG = MAX_SIG }; // Global objects ------------------------------------------------------------ QP::QMActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO &l_philo[0], &l_philo[1], &l_philo[2], &l_philo[3], &l_philo[4] }; } // namespace DPP // Philo definition ---------------------------------------------------------- $define(AOs::Philo) #include "qpcpp.h" #include "dpp.h" #include "bsp.h" Q_DEFINE_THIS_FILE // Active object class ------------------------------------------------------- $declare(AOs::Table) namespace DPP { // helper function to provide the RIGHT neighbour of a Philo[n] inline uint8_t RIGHT(uint8_t const n) { return static_cast<uint8_t>((n + (N_PHILO - 1U)) % N_PHILO); } // helper function to provide the LEFT neighbour of a Philo[n] inline uint8_t LEFT(uint8_t const n) { return static_cast<uint8_t>((n + 1U) % N_PHILO); } static uint8_t const FREE = static_cast<uint8_t>(0); static uint8_t const USED = static_cast<uint8_t>(1); static char_t const * const THINKING = &"thinking"[0]; static char_t const * const HUNGRY = &"hungry "[0]; static char_t const * const EATING = &"eating "[0]; // Local objects ------------------------------------------------------------- static Table l_table; // the single instance of the Table active object // Global-scope objects ------------------------------------------------------ QP::QMActive * const AO_Table = &l_table; // "opaque" AO pointer } // namespace DPP //............................................................................ $define(AOs::Table)