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