rtems and C++ (OOP)
Chris Johns
chrisj at rtems.org
Tue Mar 12 23:33:17 UTC 2013
Nicolás Alvarez wrote:
> Hi, anyone knows how to define a non-estatic member function of a class
> like the entry point of a task? If not, what is the best way to bind a
> function to a task according the OOP?
These days I use templates to manage this. It is more generic
programming than OOP. The pattern, I have used many times, is nice
because you separate the thread instance from the class containing the
thread and thread entry point. This means you can have more than one
thread in a class.
Chris
[ just typed this in and so not compiled or tested ]
Thread Pattern
--------------
1. Create a thread class that provides the services your threads need.
namespace threading
{
class thread_base
{
public:
// Opaque handle
typedef void* handle_type;
thread_base();
virtual ~thread_base();
void start(const int priority,
const int stacksize,
const int what_ever_else_you_need);
void stop();
protected:
virtual void entry_point() = 0;
private:
int id;
};
}
2. Create a thread template.
namespace threading
{
template<class T>
class thread
: public thread_base
{
public:
typedef void (T::*entry)();
thread() : t(0), ep(0) {}
void start(T& ref,
entry e,
const int priority,
const int stacksize,
const int what_ever_else_you_need) {
t = &ref;
ep = e;
thread_base::start(priority, stacksize, what_ever_else_you_need);
}
private:
virtual void entry_point() {
if (ep) {
try {
(t->*ep)();
}
catch (...) {
log_or_tell_the_world();
}
}
stop();
}
T* t;
entry ep;
}
}
The bit of code to call RTEMS is ...
namespace threading
{
static rtems_task c_thread_entry(rtems_task_argument arg)
{
thread_base* t = (thread_base*) arg;
t->entry_point();
// requirement of RTEMS classic tasks.
::rtems_task_delete(RTEMS_SELF);
}
void
thread_base::start(....)
{
....
sc = ::rtems_task_start(rtems_id,
c_thread_entry,
static_cast<void*>(this));
....
}
}
3. Using the template.
class worker
{
typedef threading::thread < worker > thread;
public:
worker();
~worker();
void start();
void stop();
private:
void t1_body();
void t2_body();
thread t1;
thread t2;
volatile bool t1_running;
volatile bool t2_running;
};
worker::worker() : t1_running(false), t2_running(false) {}
void
worker::start()
{
t1_running = true;
t1.start(*this, &worker.t1_body, 2, 2048, 12345678);
t2_running = true;
t2.start(*this, &worker.t2_body, 3, 2048, 87654321);
}
void
worker::stop()
{
t1_running = false;
t2_running = false;
while (t1_running || t2_running)
sleep_a_while();
}
void
worker::t1_body()
{
while (t1_running) {
printf ("hello from t1\n");
sleep_lots();
}
}
void
worker::t2_body()
{
while (t2_running) {
printf ("hello from t2\n");
sleep_lots();
}
}
More information about the users
mailing list