Author: James CE Johnson

ACE Tutorial 011
Passing non-trivial data through an ACE_Message_Queue

Our Task object declaration and definition. As with message_queue.cpp, I've only commented the changes.

task.h

    // page03.html,v 1.9 1999/04/03 21:56:27 jcej Exp

    #ifndef TASK_H
    #define TASK_H

    #include "ace/Task.h"

    #if !defined (ACE_LACKS_PRAGMA_ONCE)
    # pragma once
    #endif /* ACE_LACKS_PRAGMA_ONCE */

    class Task : public ACE_Task <ACE_MT_SYNCH>
    {
    public:

      typedef ACE_Task <ACE_MT_SYNCH> inherited;

      Task (size_t n_threads);
      ~Task (void);

      int open (void * = 0);

      int svc (void);

      int close (u_long flags = 0);

    protected:
      ACE_Barrier barrier_;

      size_t n_threads_;
    };

    #endif /* TASK_H */

task.cpp

    // page03.html,v 1.9 1999/04/03 21:56:27 jcej Exp

    #include "task.h"
    #include "block.h"
    #include "data.h"

    Task::Task (size_t n_threads)
      : barrier_ (n_threads),
        n_threads_ (n_threads)
    {
      ACE_DEBUG ((LM_DEBUG,
                  "(%P|%t) Task ctor 0x%x\n",
                  (void *) this));
    }

    Task::~Task (void)
    {
      ACE_DEBUG ((LM_DEBUG,
                  "(%P|%t) Task dtor 0x%x\n",
                  (void *) this));

      ACE_Message_Block *message;
      this->getq (message);
      message->release ();
    }

    int
    Task::open (void *)
    {
      return this->activate (THR_NEW_LWP,
                            this->n_threads_);

    }

    int
    Task::close (u_long flags)
    {
      ACE_DEBUG ((LM_DEBUG,
                  "(%P|%t) Task close 0x%x\n",
                  (void *) this));
      return inherited::close (flags);
    }

    int
    Task::svc (void)
    {
      this->barrier_.wait ();

      ACE_DEBUG ((LM_DEBUG,
                  "(%P|%t) Task 0x%x starts in thread %d\n",
                  (void *) this,
                  ACE_Thread::self ()));

      ACE_Message_Block *message;

      for (;;)
        {
          if (this->getq (message) == -1)
            ACE_ERROR_RETURN ((LM_ERROR,
                               "%p\n",
                               "getq"),
                              -1);

          if (message->msg_type () == ACE_Message_Block::MB_HANGUP)
            {
              this->putq (message);

              break;
            }

          const char *cp = message->rd_ptr ();
          // Don't forget to skip the NULL we inserted
          message->rd_ptr (ACE_OS::strlen (cp) + 1);

          ACE_DEBUG ((LM_DEBUG,
                      "(%P|%t) Block 0x%x contains (%s)\n",
                      (void *) message,
                      cp));

          /* Create a Data object into which we can extract the message
            block contents.  */
          Data data;

          /* Use the rd_ptr() to access the message block data.  Note that
            we've already moved it past the text string in the block.  */
          ACE_OS::memmove ((char *) &data,
                           message->rd_ptr (),
                           sizeof (data));
          message->rd_ptr (sizeof (data));  // Move the rd_ptr() beyond the data.

          /* Invoke a couple of method calls on the object we constructed.  */
          data.who_am_i ();
          data.what_am_i ();

          /* An alternate approach:

            Data * data;
            data = (Data *)message->rd_ptr();
            data->who_am_i();
            data->what_am_i();
            message->rd_ptr(sizeof(Data));

            Even though this cuts down on the number of copies &
            constructions, I'm not real fond of it.  You can get into
            trouble in a hurry by treating memory blocks as multiple data
            types...  */

          ACE_OS::sleep (ACE_Time_Value (0, 5000));

          message->release ();
        }

      return 0;
    }

Notice how we had to create a temporary Data object to copy the stuff out of the message block? Again, if there were non-trivial ctor/dtors involved then this wouldn't work at all.

[Tutorial Index] [Continue This Tutorial]