[LAD] Inter thread Communication: Design Approach

Gabriel Beddingfield gabrbedd at gmail.com
Sat Aug 20 15:04:46 UTC 2011


On 08/20/2011 09:19 AM, Harry van Haaren wrote:
> My (hacky?) solution: Create a class, call it "Event". Runtime now looks
> like so:
> 1. Create a EventType enum, set the details
> 2. Write those "Events" into the ringbuffer
> 3. Switch based on EventType, and handle the event.
>
> While not terribly ugly, that Event class starts to get bigger &
> nastier, so I concidered sub-classing it... but I'm not sure this is
> going in the right direction.

IMHO, You're more or less going in the right direction.  There's two 
main ways to structure your EventType.. and they are both essentially 
using inheritance.  We'll call them "The C way" and "The C++ Way".  They 
are more or less equivalent.

Consider the following to be pseudocode.  I didn't test it.

THE C WAY
=========

    struct base_event_t_ {
        uint16_t type;
        uint16_t size;
    };
    typedef struct base_event_t_ base_event_t;

    #define EVENT_ONE 1
    struct event_one_t_ {
        uint16_t type;
        uint16_t size; /* must be EVENT_ONE */
        /* extra event-specific data */
    };
    typedef struct event_one_t_ event_one_t;

    #define EVENT_TWO 2
    struct event_two_t_ {
        uint16_t type;
        uint16_t size; /* must be EVENT_TWO */
        /* extra event-specific data */
    };
    typedef struct event_one_t_;

/* ... */

    void my_function(event_t *ev)
    {
        switch(ev->type) {
        case EVENT_ONE:
            handle_event_one( (event_one_t*) ev );
            break;
        case EVENT_TWO:
            handle_event_two( (event_two_t*) ev );
            break;
        }
    }

DISADVANTAGE:  You have to manually manage the type and size arguments.

THE C++ WAY
===========

     class event_t
     {
     public:
	enum {
             EVENT_ONE = 1,
             EVENT_TWO = 2
         }; /* note: using an enum isn't necc. */

         virtual ~event_t() {}

         int type() = 0;
         uint32_t size() = 0;
     };

     class event_one_t : public event_t
     {
     public:
         int type() { return int(EVENT_ONE); }
         uint32_t size() { return sizeof(event_one); }

         /* event-specific stuff */
     };

     class event_two_t : public event_t
     {
     public:
         int type() { return int(EVENT_TWO); }
         uint32_t size() { return sizeof(event_two); }

         /* event-specific stuff */
     };

/* ... */

    void my_function(const event_t& ev)
    {
        switch(ev->type()) {
        case event_t::EVENT_ONE:
            handle_event_one( dynamic_cast<const event_one_t>(ev) );
            break;
        case event_t::EVENT_TWO:
            handle_event_two( dynamic_cast<const event_two_t>(ev) );
            break;
        }
    }

DISADVANTAGE:  Using dynamic_cast<> uses RTTI and can have a performance 
penalty... but guards against programming mistakes (throwing an 
exception if cast is invalid).  Switch to reinterpret_cast<> if speed is 
a problem.

-gabriel



More information about the Linux-audio-dev mailing list