ACE Tutorial 012
Passing classes through ACE_Message_Queue


In the previous tutorial we moved our complex data into the queue by copy()ing it directly into the message block's data area. I hope that most readers got a queasy feeling when I did that. It just isn't a good idea...

A better idea would be to teach the message queue about our data types (or at least a baseclass) so that it can more efficiently handle things:



// $Id$

#ifndef BLOCK_H
#define BLOCK_H

#include "work.h"

/*
  We derive a Message_Block from ACE_Message_Block and teach it about
  our Unit_Of_Work object.  When our task's svc() method pulls a block
  out of the queue, it can then invoke the virtual methods of the work
  object safely.  In this implementation we've also retained the
  original ACE_Message_Block functionallity so that we can use the
  underlying ACE_Data_Block objects to store data other than our
  Unit_Of_Work.
*/
class Message_Block : public ACE_Message_Block
{
public:
    typedef ACE_Message_Block inherited;

     /*
       Construct our underlying ACE_Message_Block with the requested
       data size and initialize our Unit_Of_Work pointer with the
       given object instance.  Note that this Message_Block instance
       now assumes ownership of the Unit_Of_Work and will delete it
       when the Message_Block is deleted.
     */
    Message_Block( size_t size, Unit_Of_Work * _data )
            : inherited(size), data_(_data)
        {
            ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block ctor 0x%x for 0x%x\n", (void *) this, data_));
        }

        ~Message_Block(void)
        {
            ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block dtor 0x%x for 0x%x\n", (void *) this, data_));
            delete data_;
        }

     /*
       Return the Unit_Of_Work so that the task can invoke methods on
       it.
     */
    Unit_Of_Work * data(void)
        {
            return this->data_;
        }

protected:
    Unit_Of_Work * data_;

     /*
       Disallow these very dangerous operations.
       If we were to copy a Message_Block object then the data_
       pointer would get copied and we would eventually end up
       deleting the same object multiple times!  That's not good.  By
       preventing the copy, we can avoid this.
     */
    Message_Block &operator= (const Message_Block &);
    Message_Block (const Message_Block &);
};

#endif

Ok, this looks pretty good. We just construct our specialized Message_Block instead of the generic ACE_Message_Block and let it carry our data along. When our application is done with the message block and release()es it, we know that our work object will also be taken care of.

Let's now go to main() and see what we had to change there to use this specialization.


[Tutorial Index] [Continue This Tutorial]