Dining Philosopher Problem example application
: QP::QSignal {
EAT_SIG = QP::Q_USER_SIG, // published by Table to let a Philo eat
DONE_SIG, // published by Philo when done eating
PAUSE_SIG, // published by BSP to pause the application
SERVE_SIG, // published by BSP to serve re-start serving forks
TEST_SIG, // published by BSP to test the application
MAX_PUB_SIG, // the last published signal
TIMEOUT_SIG, // posted by time event to Philo
HUNGRY_SIG, // posted by hungry Philo to Table
MAX_SIG // the last signal
};
QS_SIG_DICTIONARY(EAT_SIG, nullptr);
QS_SIG_DICTIONARY(DONE_SIG, nullptr);
QS_SIG_DICTIONARY(PAUSE_SIG, nullptr);
QS_SIG_DICTIONARY(SERVE_SIG, nullptr);
QS_SIG_DICTIONARY(TEST_SIG, nullptr);
QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr);
QS_SIG_DICTIONARY(HUNGRY_SIG, nullptr);
{5};
: QEvt(sig),
philoId(id)
: QEvt(QP::QEvt::DYNAMIC),
philoId(id)
= {
&Philo::inst[0],
&Philo::inst[1],
&Philo::inst[2],
&Philo::inst[3],
&Philo::inst[4]
};
= &Table::inst;
The Philo AO and the N_PHILO instances
: QActive(Q_STATE_CAST(&initial)),
m_timeEvt(this, TIMEOUT_SIG, 0U),
m_id(0xFFU)
Q_UNUSED_PAR(e);
m_id = static_cast<std::uint8_t>(this - &inst[0]);
QS_OBJ_ARR_DICTIONARY(&Philo::inst[m_id], m_id);
QS_OBJ_ARR_DICTIONARY(&Philo::inst[m_id].m_timeEvt, m_id);
subscribe(EAT_SIG);
subscribe(TEST_SIG);
m_timeEvt.armX(think_time(), 0U);
m_timeEvt.disarm();
// EAT or DONE must be for other Philos than this one
Q_ASSERT(Q_EVT_CAST(TableEvt)->philoId != m_id);
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, HUNGRY_SIG, m_id);
#else
TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
pe->philoId = m_id;
#endif
AO_Table->POST(pe, this);
Q_EVT_CAST(TableEvt)->philoId == m_id
// DONE must be for other Philos than this one
Q_ASSERT(Q_EVT_CAST(TableEvt)->philoId != m_id);
m_timeEvt.armX(eat_time(), 0U);
m_timeEvt.disarm();
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, DONE_SIG, m_id);
#else
TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
pe->philoId = m_id;
#endif
QP::QActive::PUBLISH(pe, this);
// EAT or DONE must be for other Philos than this one
Q_ASSERT(Q_EVT_CAST(TableEvt)->philoId != m_id);
: QActive(Q_STATE_CAST(&initial))
for (std::uint8_t n = 0U; n < N_PHILO; ++n) {
m_fork[n] = FREE;
m_isHungry[n] = false;
}
Q_UNUSED_PAR(e);
QS_OBJ_DICTIONARY(&Table::inst);
subscribe(DONE_SIG);
subscribe(PAUSE_SIG);
subscribe(SERVE_SIG);
subscribe(TEST_SIG);
for (std::uint8_t n = 0U; n < N_PHILO; ++n) {
m_fork[n] = FREE;
m_isHungry[n] = false;
BSP::displayPhilStat(n, THINKING);
}
Q_ERROR();
// give permissions to eat...
for (std::uint8_t n = 0U; n < N_PHILO; ++n) {
if (m_isHungry[n]
&& (m_fork[left(n)] == FREE)
&& (m_fork[n] == FREE))
{
m_fork[left(n)] = USED;
m_fork[n] = USED;
#ifdef QEVT_DYN_CTOR
TableEvt const *te = Q_NEW(TableEvt, EAT_SIG, n);
#else
TableEvt *te = Q_NEW(TableEvt, EAT_SIG);
te->philoId = n;
#endif
QP::QActive::PUBLISH(te, this);
m_isHungry[n] = false;
BSP::displayPhilStat(n, EATING);
}
}
std::uint8_t n = Q_EVT_CAST(TableEvt)->philoId;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!m_isHungry[n]));
BSP::displayPhilStat(n, HUNGRY);
std::uint8_t m = left(n);
(m_fork[m] == FREE) && (m_fork[n] == FREE)
m_fork[m] = USED;
m_fork[n] = USED;
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, EAT_SIG, n);
#else
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe->philoId = n;
#endif
QP::QActive::PUBLISH(pe, this);
BSP::displayPhilStat(n, EATING);
else
m_isHungry[n] = true;
std::uint8_t n = Q_EVT_CAST(TableEvt)->philoId;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!m_isHungry[n]));
BSP::displayPhilStat(n, THINKING);
std::uint8_t m = left(n);
// both forks of Phil[n] must be used
Q_ASSERT((m_fork[n] == USED) && (m_fork[m] == USED));
m_fork[m] = FREE;
m_fork[n] = FREE;
m = right(n); // check the right neighbor
if (m_isHungry[m] && (m_fork[m] == FREE)) {
m_fork[n] = USED;
m_fork[m] = USED;
m_isHungry[m] = false;
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, EAT_SIG, m);
#else
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe->philoId = m;
#endif
QP::QActive::PUBLISH(pe, this);
BSP::displayPhilStat(m, EATING);
}
m = left(n); // check the left neighbor
n = left(m); // left fork of the left neighbor
if (m_isHungry[m] && (m_fork[n] == FREE)) {
m_fork[m] = USED;
m_fork[n] = USED;
m_isHungry[m] = false;
#ifdef QEVT_DYN_CTOR
TableEvt const *pe = Q_NEW(TableEvt, EAT_SIG, m);
#else
TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
pe->philoId = m;
#endif
QP::QActive::PUBLISH(pe, this);
BSP::displayPhilStat(m, EATING);
}
Q_ERROR();
BSP::displayPaused(1U);
BSP::displayPaused(0U);
std::uint8_t n = Q_EVT_CAST(TableEvt)->philoId;
// philo ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!m_isHungry[n]));
m_isHungry[n] = true;
BSP::displayPhilStat(n, HUNGRY);
std::uint8_t n = Q_EVT_CAST(TableEvt)->philoId;
// phil ID must be in range and he must be not hungry
Q_ASSERT((n < N_PHILO) && (!m_isHungry[n]));
BSP::displayPhilStat(n, THINKING);
std::uint8_t m = left(n);
// both forks of Phil[n] must be used
Q_ASSERT((m_fork[n] == USED) && (m_fork[m] == USED));
m_fork[m] = FREE;
m_fork[n] = FREE;
#ifndef DPP_HPP_
#define DPP_HPP_
$declare ${Shared}
#ifdef QXK_HPP_
namespace APP {
extern QP::QXThread * const TH_XThread1;
extern QP::QXThread * const TH_XThread2;
extern QP::QXSemaphore TH_sema;
extern QP::QXMutex TH_mutex;
} // namespace APP
#endif // QXK_HPP_
#endif // DPP_HPP_
#include "qpcpp.hpp" // QP/C++ real-time embedded framework
#include "dpp.hpp" // DPP Application interface
#include "bsp.hpp" // Board Support Package
//----------------------------------------------------------------------------
namespace { // unnamed namespace for local definitions with internal linkage
Q_DEFINE_THIS_FILE
// helper function to provide a randomized think time for Philos
static 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
static inline QP::QTimeEvtCtr eat_time() {
return static_cast<QP::QTimeEvtCtr>((BSP::random() % BSP::TICKS_PER_SEC)
+ BSP::TICKS_PER_SEC);
}
} // unnamed namespace
//----------------------------------------------------------------------------
$declare ${AOs::Philo}
$define ${Shared::AO_Philo[N_PHILO]}
$define ${AOs::Philo}
#include "qpcpp.hpp" // QP/C++ real-time embedded framework
#include "dpp.hpp" // DPP Application interface
#include "bsp.hpp" // Board Support Package
$declare ${AOs::Table}
//----------------------------------------------------------------------------
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_FILE
// helper function to provide the RIGHT neighbour of a Philo[n]
static inline std::uint8_t right(std::uint8_t const n) {
return static_cast<std::uint8_t>((n + (APP::N_PHILO - 1U)) % APP::N_PHILO);
}
// helper function to provide the LEFT neighbour of a Philo[n]
static inline std::uint8_t left(std::uint8_t const n) {
return static_cast<std::uint8_t>((n + 1U) % APP::N_PHILO);
}
static constexpr std::uint8_t FREE {0U};
static constexpr std::uint8_t USED {1U};
static constexpr char const * const THINKING {"thinking"};
static constexpr char const * const HUNGRY {"hungry "};
static constexpr char const * const EATING {"eating "};
} // unnamed namespace
//----------------------------------------------------------------------------
$define ${Shared::AO_Table}
$define ${AOs::Table}