winston 发表于 2012-2-29 00:19:06

ACE_Message_Block-----ACE消息的存储

ACE_Message_Block在Ace中用来表示消息的存放空间,可用做网络通信中的消息缓冲区,使用非常频繁,下面将在如下方简单的介绍一下ACE_Message_Block相关功能。使用案例: view plaincopyprint?


[*]ACE_Message_Block * head = NULL;
[*]ACE_NEW_RETURN(head, ACE_Message_Block( sizeof( void * ) ), -1 );
[*]ACE_Message_Block *msg = head;
[*]ACE_OS::memcpy( msg->wr_ptr(), &pMsg,sizeof( void *) );
[*]msg->wr_ptr(sizeof( void *));

    ACE_Message_Block * head = NULL;    ACE_NEW_RETURN(head, ACE_Message_Block( sizeof( void * ) ), -1 );    ACE_Message_Block *msg = head;    ACE_OS::memcpy( msg->wr_ptr(), &pMsg,sizeof( void *) );    msg->wr_ptr(sizeof( void *)); 下面是转自网络:1。创建消息块 创建消息块的方式比较灵活,常用的有以下几种方式 : 1。直接给消息块分配内存空间创建。     ACE_Message_Block *mb =new ACE_Message_Block (30); 2。共享底层数据块创建。     char buffer;
    ACE_Message_Block *mb = new ACE_Message_Block (buffer,30);这种方式共享底层的数据块,被创建的消息块并不拷贝该数据,也不假定自己拥有它的所有权。在消息块mb被销毁时,相关联的数据缓冲区data将不会被销毁。这是有意义的:消息块没有拷贝数据,因此内存也不是它分配的,这样它也不应该负责销毁它。3。通过duplicate()函数从已有的消息块中创建副本。     ACE_Message_Block *mb =new ACE_Message_Block (30);
    ACE_Message_Block *mb2 = mb->duplicate(); 这种方式下,mb2和mb共享同一数据空间,使用的是ACE_Message_Block的引用计数机制。它返回指向要被复制的消息块的指针,并在内部增加内部引用计数。4。通过clone()函数从已有的消息块中复制。     ACE_Message_Block *mb =new ACE_Message_Block (30);
    ACE_Message_Block *mb2 = mb->clone(); clone()方法实际地创建整个消息块的新副本,包括它的数据块和附加部分;也就是说,这是一次"深拷贝"。2。释放消息块 一旦使用完消息块,程序员可以调用它的release()方法来释放它。
[*]如果消息数据内存是由该消息块分配的,调用release()方法就也会释放此内存。
[*]如果消息块是引用计数的,release()就会减少计数,直到到达0为止;之后消息块和与它相关联的数据块才从内存中被移除。
[*]如果消息块是通过共享已分配的底层数据块创建的,底层数据块不会被释放。
无论消息块是哪种方式创建的,只要在使用完后及时调用release()函数,就能确保相应的内存能正确的释放。 3。从消息块中读写数据 ACE_Message_Block提供了两个指针函数以供程序员进行读写操作,rd_ptr()指向可读的数据块地址,wr_ptr()指向可写的数据块地址,默认情况下都执行数据块的首地址。下面的例子简单了演示它的使用方法。#include"ace/Message_Queue.h"
#include "ace/OS.h"

int main(int argc,char *argv[])
{
    ACE_Message_Block *mb = new ACE_Message_Block (30);
    ACE_OS::sprintf(mb->wr_ptr(),"%s","hello");
    ACE_OS::printf("%s\n",mb->rd_ptr ());
    mb->release();
    return 0;
} 注意:这两个指针所指向的位置并不会自动移动,在上面的例子中,函数执行完毕后,执行的位置仍然是最开始的0,而不是最新的可写位置5,程序员需要通过wr_ptr(5)函数手动移动写指针的位置。4。数据的拷贝 一般的数据的拷贝可以通过函数来实现数据的拷贝,copy()还会保证wr_ptr()的更新,使其指向缓冲区的新末尾处。 下面的例子演示了copy()函数的用法。     mb->copy("hello");
    mb->copy("123",4); 注意:由于c++是以'\0'作为字符串结束标志的,对于上面的例子,底层数据块中保存的是"hello\0123\0",而用ACE_OS::printf("%s\n",mb->rd_ptr ());打印出来的结果是"hello",使用copy函数进行字符串连接的时候需要注意。5。其它常用函数
[*]length()    返回当前的数据长度
[*]next()    获取和设置下一个ACE_Message_Block的链接。(用来建立消息队列非常有用)
[*]space()    获取剩余可用空间大小
[*]size()    获取和设置数据存储空间大小。
下面是源代码,可以直接调用,对数据块操作:
view plaincopyprint?


[*]// -*- C++ -*-
[*]
[*]//==========================================================================
[*]/**
[*] *@file    Message_Block.h
[*] *
[*] *$Id: Message_Block.h 93359 2011-02-11 11:33:12Z mcorino $
[*] *
[*] *@author Douglas C. Schmidt <schmidt@cs.wustl.edu>
[*] */
[*]//==========================================================================
[*]
[*]#ifndef ACE_MESSAGE_BLOCK_H
[*]#define ACE_MESSAGE_BLOCK_H
[*]
[*]#include /**/ "ace/pre.h"
[*]
[*]#include "ace/config-lite.h"
[*]#include /**/ "ace/ACE_export.h"
[*]
[*]#if !defined (ACE_LACKS_PRAGMA_ONCE)
[*]# pragma once
[*]#endif /* ACE_LACKS_PRAGMA_ONCE */
[*]
[*]#include "ace/Default_Constants.h"
[*]#include "ace/Global_Macros.h"
[*]#include "ace/Time_Value.h"
[*]
[*]ACE_BEGIN_VERSIONED_NAMESPACE_DECL
[*]
[*]// Forward declaration.
[*]class ACE_Allocator;
[*]class ACE_Data_Block;
[*]class ACE_Lock;
[*]
[*]
[*]/**
[*] * @class ACE_Message_Block
[*] *
[*] * @brief Stores messages for use throughout ACE (particularly
[*] * in an ACE_Message_Queue).
[*] *
[*] * An ACE_Message_Block is modeled after the message data
[*] * structures used in System V STREAMS.Its purpose is to
[*] * enable efficient manipulation of arbitrarily large messages
[*] * without incurring much memory copying overhead.Here are the
[*] * main characteristics of an ACE_Message_Block:
[*] * - Contains a pointer to a reference-counted
[*] *   ACE_Data_Block, which in turn points to the actual data
[*] *   buffer.This allows very flexible and efficient sharing of
[*] *   data by multiple ACE_Message_Block objects.
[*] * - One or more ACE_Message_Blocks can be linked to form a
[*] *    ``fragment chain.''
[*] * - ACE_Message_Blocks can be linked together in a doubly linked fashion
[*] *   to form a queue of messages (this is how ACE_Message_Queue works).
[*] *
[*] * @see C++NPv1, section 4.2; APG, section 12.3.2.
[*] */
[*]class ACE_Export ACE_Message_Block
[*]{
[*]public:
[*]friend class ACE_Data_Block;
[*]
[*]enum
[*]{
[*]    // = Data and proto
[*]    /// Undifferentiated data message
[*]    MB_DATA   = 0x01,
[*]    /// Undifferentiated protocol control
[*]    MB_PROTO    = 0x02,
[*]
[*]    // = Control messages
[*]    /// Line break (regular and priority)
[*]    MB_BREAK    = 0x03,
[*]    /// Pass file pointer
[*]    MB_PASSFP   = 0x04,
[*]    /// Post an event to an event queue
[*]    MB_EVENT    = 0x05,
[*]    /// Generate process signal
[*]    MB_SIG      = 0x06,
[*]    /// ioctl; set/get params
[*]    MB_IOCTL    = 0x07,
[*]    /// Set various stream head options
[*]    MB_SETOPTS= 0x08,
[*]
[*]    // = Control messages
[*]    /// Acknowledge ioctl (high priority; go to head of queue)
[*]    MB_IOCACK   = 0x81,
[*]    /// Negative ioctl acknowledge
[*]    MB_IOCNAK   = 0x82,
[*]    /// Priority proto message
[*]    MB_PCPROTO= 0x83,
[*]    /// Generate process signal
[*]    MB_PCSIG    = 0x84,
[*]    /// Generate read notification
[*]    MB_READ   = 0x85,
[*]    /// Flush your queues
[*]    MB_FLUSH    = 0x86,
[*]    /// Stop transmission immediately
[*]    MB_STOP   = 0x87,
[*]    /// Restart transmission after stop
[*]    MB_START    = 0x88,
[*]    /// Line disconnect
[*]    MB_HANGUP   = 0x89,
[*]    /// Fatal error used to set u.u_error
[*]    MB_ERROR    = 0x8a,
[*]    /// Post an event to an event queue
[*]    MB_PCEVENT= 0x8b,
[*]
[*]    // = Message class masks
[*]    /// Normal priority message mask
[*]    MB_NORMAL   = 0x00,
[*]    /// High priority control message mask
[*]    MB_PRIORITY = 0x80,
[*]    /// User-defined message mask
[*]    MB_USER   = 0x200
[*]};
[*]
[*]typedef int ACE_Message_Type;
[*]typedef unsigned long Message_Flags;
[*]
[*]enum
[*]{
[*]    /// Don't delete the data on exit since we don't own it.
[*]    DONT_DELETE = 01,
[*]    /// user defined flags start here
[*]    USER_FLAGS = 0x1000
[*]};
[*]
[*]// = Initialization and termination.
[*]/// Create an empty message.
[*]ACE_Message_Block (ACE_Allocator *message_block_allocator = 0);
[*]
[*]/**
[*]   * Create an ACE_Message_Block that owns the specified ACE_Data_Block
[*]   * without copying it. If the @a flags is set to @c DONT_DELETE we
[*]   * don't delete the ACE_Data_Block. It is left to the client's
[*]   * responsibility to take care of the memory allocated for the
[*]   * data_block
[*]   */
[*]<strong>ACE_Message_Block (ACE_Data_Block *data_block,
[*]                     Message_Flags flags = 0,
[*]                     ACE_Allocator *message_block_allocator = 0);</strong>
[*]
[*]/**
[*]   * Create an ACE_Message_Block that refers to @a data without
[*]   * copying it. The @a data memory will not be freed when this block is
[*]   * destroyed; memory management of @a data is left to the caller.
[*]   * Note that the @c size of the new ACE_Message_Block will be @a size, but
[*]   * the @c length will be 0 until the write pointer is changed.
[*]   */
[*]ACE_Message_Block (const char *data,
[*]                     size_t size = 0,
[*]                     unsigned long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY);
[*]
[*]/**
[*]   * Create an initialized message of type @a type containing @a size
[*]   * bytes.The @a cont argument initializes the continuation field in
[*]   * the ACE_Message_Block.If @a data == 0 then this block allocates and
[*]   * owns the block's memory, using @a allocator to get the data if it's
[*]   * non-0.If @a data != 0 then this block refers to that memory until
[*]   * this this block ceases to exist; this object will not free @a data on
[*]   * destruction.If @a locking_strategy is non-0 then this is used
[*]   * to protect regions of code that access shared state (e.g.,
[*]   * reference counting) from race conditions.Note that the @c size
[*]   * of the ACE_Message_Block will be @a size, but the @c length will be 0
[*]   * until the write pointer is set. The @a data_block_allocator is used to
[*]   * allocate the data blocks while the @a allocator_strategy is used
[*]   * to allocate the buffers contained by those. The
[*]   * @a message_block_allocator is used to allocate new ACE_Message_Block
[*]   * objects when the duplicate() method is called. If a
[*]   * @a message_block_allocator is given, this ACE_Message_Block and
[*]   * future ACE_Message_Block objects created by duplicate() will be
[*]   * freed using this allocator when they are released.
[*]   * @note If you use this allocator, the ACE_Message_Block you created
[*]   * should have been created using this allocator because it will be
[*]   * released to the same allocator.
[*]   */
[*] <strong> ACE_Message_Block (size_t size,
[*]                     ACE_Message_Type type = MB_DATA,
[*]                     ACE_Message_Block *cont = 0,
[*]                     const char *data = 0,
[*]                     ACE_Allocator *allocator_strategy = 0,
[*]                     ACE_Lock *locking_strategy = 0,
[*]                     unsigned long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY,
[*]                     const ACE_Time_Value &execution_time = ACE_Time_Value::zero,
[*]                     const ACE_Time_Value &deadline_time = ACE_Time_Value::max_time,
[*]                     ACE_Allocator *data_block_allocator = 0,
[*]                     ACE_Allocator *message_block_allocator = 0);</strong>
[*]
[*]/**
[*]   * A copy constructor. This constructor is a bit different. If the
[*]   * incoming Message Block has a data block from the stack this
[*]   * constructor does a deep copy ie. allocates a new data block on
[*]   * the heap and does a copy of the data from the incoming message
[*]   * block. As a final note, the alignment information is used to
[*]   * align the data block if it is created afresh. If the incoming
[*]   * @a mb has a data block has a data block allocated from the heap,
[*]   * then this constructor just duplicates (ie. a shallow copy) the
[*]   * data block of the incoming @a mb.
[*]   */
[*]ACE_Message_Block (const ACE_Message_Block &mb,
[*]                     size_t align);
[*]
[*]/**
[*]   * Create a Message Block that assumes it has ownership of @a data,
[*]   * but in reality it doesnt (i.e., cannot delete it since it didn't
[*]   * malloc it!).Note that the @c size of the Message_Block will
[*]   * be @a size, but the @a lengthwill be 0 until <wr_ptr> is set.
[*]   */
[*] <span style="font-size:18px;"><strong> int init (const char *data,
[*]            size_t size = 0);</strong>
[*]</span>
[*]/**
[*]   * Create an initialized message of type @a type containing @a size
[*]   * bytes.The @a cont argument initializes the continuation field in
[*]   * the Message_Block.If @a data == 0 then we create and own the
[*]   * @a data, using @a allocator_strategy to get the data if it's non-0.If
[*]   * @a data != 0 we assume that we have ownership of the @a data till
[*]   * this object ceases to exist(and don't delete it during
[*]   * destruction).If @a locking_strategy is non-0 then this is used
[*]   * to protect regions of code that access shared state (e.g.,
[*]   * reference counting) from race conditions.Note that the @a size
[*]   * of the Message_Block will be @a size, but the @a length will be 0
[*]   * until <wr_ptr> is set. The @a data_block_allocator is use to
[*]   * allocate the data blocks while the @a allocator_strategy is used
[*]   * to allocate the buffers contained by those.
[*]   */
[*]int init (size_t size,
[*]            ACE_Message_Type type = MB_DATA,
[*]            ACE_Message_Block *cont = 0,
[*]            const char *data = 0,
[*]            ACE_Allocator *allocator_strategy = 0,
[*]            ACE_Lock *locking_strategy = 0,
[*]            unsigned long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY,
[*]            const ACE_Time_Value &execution_time = ACE_Time_Value::zero,
[*]            const ACE_Time_Value &deadline_time = ACE_Time_Value::max_time,
[*]            ACE_Allocator *data_block_allocator = 0,
[*]            ACE_Allocator *message_block_allocator = 0);
[*]
[*]/**
[*]   * Delete all the resources held in the message.
[*]   *
[*]   * @note Note that release() is designed to release the continuation
[*]   * chain; the destructor is not. See release() for details.
[*]   */
[*] <strong><span style="font-size:16px;"> virtual ~ACE_Message_Block (void);
[*]</span></strong>
[*]// = Message Type accessors and mutators.
[*]
[*]/// Get type of the message.
[*]<span style="font-size:16px;"><strong>ACE_Message_Type msg_type (void) const;
[*]</strong></span>
[*]/// Set type of the message.
[*]void msg_type (ACE_Message_Type type);
[*]
[*]/// Find out what type of message this is.
[*]int is_data_msg (void) const;
[*]
[*]/// Find out what class of message this is (there are two classes,
[*]/// @c normal messages and @c high-priority messages).
[*]ACE_Message_Type msg_class (void) const;
[*]
[*]// = Message flag accessors and mutators.
[*]/// Bitwise-or the @a more_flags into the existing message flags and
[*]/// return the new value.
[*]Message_Flags set_flags (Message_Flags more_flags);
[*]
[*]/// Clear the message flag bits specified in @a less_flags and return
[*]/// the new value.
[*]Message_Flags clr_flags (Message_Flags less_flags);
[*]
[*]/// Get the current message flags.
[*]<span style="font-size:18px;"><strong>Message_Flags flags (void) const;</strong>
[*]</span>
[*]// = Data Block flag accessors and mutators.
[*]/// Bitwise-or the @a more_flags into the existing message flags and
[*]/// return the new value.
[*]/* @todo: I think the following set of methods could not be used at
[*]   *all. May be they are useless. Let us have it so that we dont
[*]   *mess up memory management of the Message_Block. Somebody correct
[*]   *me if I am totally totally wrong..
[*]   */
[*] <span style="font-size:18px;"><strong> Message_Flags set_self_flags (ACE_Message_Block::Message_Flags more_flags);</strong>
[*]</span>
[*]/// Clear the message flag bits specified in @a less_flags and return
[*]/// the new value.
[*]<span style="font-size:18px;"><strong>Message_Flags clr_self_flags (ACE_Message_Block::Message_Flags less_flags);</strong>
[*]</span>
[*]/// Get the current message flags.
[*]<strong><span style="font-size:18px;">Message_Flags self_flags (void) const;
[*]</span></strong>
[*]/// Get priority of the message.
[*]<span style="font-size:18px;"><strong>unsigned long msg_priority (void) const;
[*]</strong></span>
[*]/// Set priority of the message.
[*]<span style="font-size:18px;"><strong>void msg_priority (unsigned long priority);
[*]</strong></span>
[*]/// Get execution time associated with the message.
[*]<span style="font-size:18px;"><strong>const ACE_Time_Value &msg_execution_time (void) const;</strong>
[*]</span>
[*]/// Set execution time associated with the message.
[*] <span style="font-size:18px;"><strong> void msg_execution_time (const ACE_Time_Value &et);
[*]
[*]</strong></span>/// Get absolute time of deadline associated with the message.
[*]<span style="font-size:18px;"><strong>const ACE_Time_Value &msg_deadline_time (void) const;</strong>
[*]</span>
[*]/// Set absolute time of deadline associated with the message.
[*]<strong><span style="font-size:18px;">void msg_deadline_time (const ACE_Time_Value &dt);
[*]</span></strong>
[*]// = Deep copy and shallow copy methods.
[*]
[*]/// Return an exact "deep copy" of the message, i.e., create fresh
[*]/// new copies of all the Data_Blocks and continuations.
[*]virtual ACE_Message_Block *clone (Message_Flags mask = 0) const;
[*]
[*]/// Return a "shallow" copy that increments our reference count by 1.
[*]virtual ACE_Message_Block *duplicate (void) const;
[*]
[*]/**
[*]   * Return a "shallow" copy that increments our reference count by 1.
[*]   * This is similar to CORBA's <_duplicate> method, which is useful
[*]   * if you want to eliminate lots of checks for NULL @a mb pointers
[*]   * before calling <_duplicate> on them.
[*]   */
[*]<span style="font-size:18px;"><strong>static ACE_Message_Block *duplicate (const ACE_Message_Block *mb);</strong>
[*]</span>
[*]/**
[*]   * Decrease the shared ACE_Data_Block's reference count by 1.If the
[*]   * ACE_Data_Block's reference count goes to 0, it is deleted.
[*]   * In all cases, this ACE_Message_Block is deleted - it must have come
[*]   * from the heap, or there will be trouble.
[*]   *
[*]   * release() is designed to release the continuation chain; the
[*]   * destructor is not.If we make the destructor release the
[*]   * continuation chain by calling release() or delete on the message
[*]   * blocks in the continuation chain, the following code will not
[*]   * work since the message block in the continuation chain is not off
[*]   * the heap:
[*]   *
[*]   *ACE_Message_Block mb1 (1024);
[*]   *ACE_Message_Block mb2 (1024);
[*]   *
[*]   *mb1.cont (&mb2);
[*]   *
[*]   * And hence, call release() on a dynamically allocated message
[*]   * block. This will release all the message blocks in the
[*]   * continuation chain.If you call delete or let the message block
[*]   * fall off the stack, cleanup of the message blocks in the
[*]   * continuation chain becomes the responsibility of the user.
[*]   *
[*]   * @retval 0, always, and the object this method was invoked on is no
[*]   *            longer valid.
[*]   */
[*]virtual ACE_Message_Block *release (void);
[*]
[*]/**
[*]   * This behaves like the non-static method <release>, except that it
[*]   * checks if @a mb is 0.This is similar to <CORBA::release>, which
[*]   * is useful if you want to eliminate lots of checks for NULL
[*]   * pointers before calling <release> on them.Returns @a mb.
[*]   */
[*]static ACE_Message_Block *release (ACE_Message_Block *mb);
[*]
[*]// = Operations on Message data
[*]
[*]/**
[*]   * Copies data into this ACE_Message_Block. Data is copied into the
[*]   * block starting at the current write pointer.
[*]   *
[*]   * @param bufPointer to the buffer to copy from.
[*]   * @param n    The number of bytes to copy.
[*]   *
[*]   * @retval 0on success; the write pointer is advanced by @arg n.
[*]   * @retval -1 if the amount of free space following the write pointer
[*]   *            in the block is less than @arg n. Free space can be checked
[*]   *            by calling space().
[*]   */
[*]<span style="font-size:18px;"><strong>int copy (const char *buf, size_t n);</strong>
[*]</span>
[*]/**
[*]   * Copies a 0-terminated character string into this ACE_Message_Block.
[*]   * The string is copied into the block starting at the current write
[*]   * pointer. The 0-terminator is included in the copied data.
[*]   *
[*]   * @param bufPointer to the character string to copy from.
[*]   *
[*]   * @retval 0on success; the write pointer is advanced by the string's
[*]   *            length, including the 0 terminator.
[*]   * @retval -1 if the amount of free space following the write pointer
[*]   *            in the block is less than required to hold the entire string.
[*]   *            Free space can be checked by calling space().
[*]   */
[*]<span style="font-size:18px;"><strong>int copy (const char *buf);</strong>
[*]</span>
[*]/// Normalizes data in the top-level Message_Block to align with the base,
[*]/// i.e., it "shifts" the data pointed to by <rd_ptr> down to the <base> and
[*]/// then readjusts <rd_ptr> to point to <base> and <wr_ptr> to point
[*]/// to <base> + the length of the moved data.Returns -1 and does
[*]/// nothing if the <rd_ptr> is > <wr_ptr>, else 0 on success.
[*]<span style="font-size:18px;"><strong>int crunch (void);</strong>
[*]</span>
[*]/// Resets the Message Block data to contain nothing, i.e., sets the
[*]/// read and write pointers to align with the base.
[*]<span style="font-size:18px;"><strong>void reset (void);</strong>
[*]</span>
[*]/// Access all the allocators in the message block.
[*]/// @todo Not sure whether we would need finer control while
[*]/// trying to access allocators ie. a method for every allocator.
[*]/**
[*]   * This method returns the allocators only from the first message
[*]   * block in the chain.
[*]   *
[*]   * @param allocator_strategy Strategy used to allocate the
[*]   *                           underlying buffer
[*]   *
[*]   * @param data_block_allocator Strategy used to allocate the
[*]   *                           underlying data block
[*]   *
[*]   * @param message_block_allocator Strategy used to allocate the
[*]   *                              message block
[*]   */
[*]<span style="font-size:18px;"><strong>void access_allocators (ACE_Allocator *&allocator_strategy,
[*]                        ACE_Allocator *&data_block_allocator,
[*]                        ACE_Allocator *&message_block_allocator);</strong>
[*]</span>
[*]/// Reset all the allocators in the message block.
[*]/// @todo Not sure whether we would need finer control while
[*]/// trying to reset allocators ie. a method for every allocator.
[*]/**
[*]   * This method resets the allocators in all the message blocks in
[*]   * the chain.
[*]   */
[*]<span style="font-size:18px;"><strong>void reset_allocators (ACE_Allocator *allocator_strategy = 0,
[*]                         ACE_Allocator *data_block_allocator = 0,
[*]                         ACE_Allocator *message_block_allocator = 0);</strong>
[*]
[*]</span>/// Get message data.
[*]<span style="font-size:18px;"><strong>char *base (void) const;</strong>
[*]</span>
[*]/// Set message data (doesn't reallocate).
[*]<span style="font-size:18px;"><strong>void base (char *data,
[*]             size_t size,
[*]             Message_Flags = DONT_DELETE);</strong>
[*]</span>
[*]/// Return a pointer to 1 past the end of the allocated data in a message.
[*]char *end (void) const;
[*]
[*]/**
[*]   * Return a pointer to 1 past the end of the allotted data in a message.
[*]   * Allotted data may be less than allocated dataif a value smaller than
[*]   * capacity() to is passed to size().
[*]   */
[*] <span style="font-size:18px;"><strong> char *mark (void) const;</strong>
[*]</span>
[*]/// Get the read pointer.
[*]<span style="font-size:24px;"><strong>char *rd_ptr (void) const;</strong>
[*]
[*]</span>/// Set the read pointer to @a ptr.
[*] <span style="font-size:18px;"><strong> void rd_ptr (char *ptr);</strong>
[*]</span>
[*]/// Set the read pointer ahead @a n bytes.
[*]<span style="font-size:18px;"><strong>void rd_ptr (size_t n);</strong>
[*]</span>
[*]/// Get the write pointer.
[*]<strong><span style="font-size:18px;">char *wr_ptr (void) const;
[*]</span></strong>
[*]/// Set the write pointer to @a ptr.
[*] <span style="font-size:18px;"><strong> void wr_ptr (char *ptr);</strong>
[*]</span>
[*]/// Set the write pointer ahead @a n bytes.This is used to compute
[*]/// the <length> of a message.
[*]<span style="font-size:18px;"><strong>void wr_ptr (size_t n);</strong>
[*]</span>
[*]/** @name Message length and size operations
[*]   *
[*]   * Message length is (wr_ptr - rd_ptr).
[*]   *
[*]   * Message size is capacity of the message, including data outside
[*]   * the range.
[*]   */
[*]//@{
[*]/// Get the length of the message
[*]<span style="font-size:18px;"><strong>size_t length (void) const;</strong>
[*]</span>
[*]/// Set the length of the message
[*]<span style="font-size:18px;"><strong>void length (size_t n);</strong>
[*]</span>
[*]/// Get the length of the Message_Blocks, including chained
[*]/// Message_Blocks.
[*]<span style="font-size:18px;"><strong>size_t total_length (void) const;</strong>
[*]
[*]</span>/// Get the total number of bytes in all Message_Blocks, including
[*]/// chained Message_Blocks.
[*]<span style="font-size:18px;"><strong>size_t total_size (void) const;</strong>
[*]</span>
[*]/// Get the total number of bytes and total length in all
[*]/// Message_Blocks, including chained Message_Blocks.
[*]<span style="font-size:18px;"><strong>void total_size_and_length (size_t &mb_size,
[*]                              size_t &mb_length) const;</strong>
[*]</span>
[*]/// Get the number of bytes in the top-level Message_Block (i.e.,
[*]/// does not consider the bytes in chained Message_Blocks).
[*]<span style="font-size:18px;"><strong>size_t size (void) const;</strong>
[*]</span>
[*]/**
[*]   * Set the number of bytes in the top-level Message_Block,
[*]   * reallocating space if necessary.However, the @c rd_ptr_ and
[*]   * @c wr_ptr_ remain at the original offsets into the buffer, even if
[*]   * it is reallocated.Returns 0 if successful, else -1.
[*]   <span style="font-size:18px;"><strong>*/
[*]int size (size_t length);</strong>
[*]</span>
[*]/// Get the number of allocated bytes in all Message_Block, including
[*]/// chained Message_Blocks.
[*] <span style="font-size:18px;"><strong> size_t total_capacity (void) const;</strong>
[*]</span>
[*]/// Get the number of allocated bytes in the top-level Message_Block.
[*] <span style="font-size:18px;"><strong> size_t capacity (void) const;</strong>
[*]</span>
[*]/// Get the number of bytes available after the <wr_ptr_> in the
[*]/// top-level Message_Block.
[*] <strong><span style="font-size:18px;"> size_t space (void) const;
[*]</span></strong>//@}
[*]
[*]// = ACE_Data_Block methods.
[*]
[*]/**
[*]   * Get a pointer to the data block. Note that the ACE_Message_Block
[*]   * still references the block; this call does not change the reference
[*]   * count.
[*]   */
[*]ACE_Data_Block *data_block (void) const;
[*]
[*]/**
[*]   * Set a new data block pointer. The original ACE_Data_Block is released
[*]   * as a result of this call. If you need to keep the original block, call
[*]   * <replace_data_block> instead. Upon return, this ACE_Message_Block
[*]   * holds a pointer to the new ACE_Data_Block, taking over the reference
[*]   * you held on it prior to the call.
[*]   */
[*]void data_block (ACE_Data_Block *);
[*]
[*]/// Set a new data block pointer. A pointer to the original ACE_Data_Block
[*]/// is returned, and not released (as it is with <data_block>).
[*]ACE_Data_Block *replace_data_block (ACE_Data_Block*);
[*]
[*]// = The continuation field chains together composite messages.
[*]/// Get the continuation field.
[*]ACE_Message_Block *cont (void) const;
[*]
[*]/// Set the continuation field.
[*]void cont (ACE_Message_Block *);
[*]
[*]// = Pointer to the Message_Block directly ahead in the ACE_Message_Queue.
[*]/// Get link to next message.
[*]<span style="font-size:18px;"><strong>ACE_Message_Block *next (void) const;</strong>
[*]</span>
[*]/// Set link to next message.
[*] <span style="font-size:18px;"><strong> void next (ACE_Message_Block *);</strong>
[*]
[*]</span>// = Pointer to the Message_Block directly behind in the ACE_Message_Queue.
[*]/// Get link to prev message.
[*]<span style="font-size:18px;"><strong>ACE_Message_Block *prev (void) const;</strong>
[*]</span>
[*]/// Set link to prev message.
[*]<span style="font-size:18px;"><strong>void prev (ACE_Message_Block *);</strong>
[*]</span>
[*]// = The locking strategy prevents race conditions.
[*]/// Get the locking strategy.
[*]ACE_Lock *locking_strategy (void);
[*]
[*]/// Set a new locking strategy and return the hold one.
[*]ACE_Lock *locking_strategy (ACE_Lock *);
[*]
[*]/// Get the current reference count.
[*]int reference_count (void) const;
[*]
[*]/// Dump the state of an object.
[*]void dump (void) const;
[*]
[*]/// Declare the dynamic allocation hooks.
[*]ACE_ALLOC_HOOK_DECLARE;
[*]
[*]protected:
[*]// = Internal initialization methods.
[*]/// Perform the actual initialization.
[*]ACE_Message_Block (size_t size,
[*]                     ACE_Message_Type type,
[*]                     ACE_Message_Block *cont,
[*]                     const char *data,
[*]                     ACE_Allocator *allocator_strategy,
[*]                     ACE_Lock *locking_strategy,
[*]                     Message_Flags flags,
[*]                     unsigned long priority,
[*]                     const ACE_Time_Value &execution_time,
[*]                     const ACE_Time_Value &deadline_time,
[*]                     ACE_Data_Block *db,
[*]                     ACE_Allocator *data_block_allocator,
[*]                     ACE_Allocator *message_block_allocator);
[*]
[*]/// Internal release implementation
[*]/// Returns 1 if the data block has to be destroyed.
[*]int release_i (ACE_Lock *lock);
[*]
[*]/// Perform the actual initialization.
[*]int init_i (size_t size,
[*]            ACE_Message_Type type,
[*]            ACE_Message_Block *cont,
[*]            const char *data,
[*]            ACE_Allocator *allocator_strategy,
[*]            ACE_Lock *locking_strategy,
[*]            Message_Flags flags,
[*]            unsigned long priority,
[*]            const ACE_Time_Value &execution_time,
[*]            const ACE_Time_Value &deadline_time,
[*]            ACE_Data_Block *db,
[*]            ACE_Allocator *data_block_allocator,
[*]            ACE_Allocator *message_block_allocator);
[*]
[*]/// Pointer to beginning of next read.
[*]size_t rd_ptr_;
[*]
[*]/// Pointer to beginning of next write.
[*]size_t wr_ptr_;
[*]
[*]/// Priority of message.
[*]unsigned long priority_;
[*]
[*]#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
[*]/// Execution time associated with the message.
[*]ACE_Time_Value execution_time_;
[*]
[*]/// Absolute deadline time for message.
[*]ACE_Time_Value deadline_time_;
[*]#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
[*]
[*]// = Links to other ACE_Message_Block *s.
[*]/// Pointer to next message block in the chain.
[*]ACE_Message_Block *cont_;
[*]
[*]/// Pointer to next message in the list.
[*]ACE_Message_Block *next_;
[*]
[*]/// Pointer to previous message in the list.
[*]ACE_Message_Block *prev_;
[*]
[*]/// Misc flags (e.g., DONT_DELETE and USER_FLAGS).
[*]ACE_Message_Block::Message_Flags flags_;
[*]
[*]/// Pointer to the reference counted data structure that contains the
[*]/// actual memory buffer.
[*]ACE_Data_Block *data_block_;
[*]
[*]/// The allocator used to destroy ourselves when release is called
[*]/// and create new message blocks on duplicate.
[*]ACE_Allocator *message_block_allocator_;
[*]
[*]private:
[*]// = Disallow these operations for now (use <clone> instead).
[*]ACE_Message_Block &operator= (const ACE_Message_Block &);
[*]ACE_Message_Block (const ACE_Message_Block &);
[*]};
[*]
[*]/**
[*] * @class ACE_Data_Block
[*] *
[*] * @brief Stores the data payload that is accessed via one or more
[*] * ACE_Message_Block's.
[*] *
[*] * This data structure is reference counted to maximize
[*] * sharing.It also contains the <locking_strategy_> (which
[*] * protects the reference count from race conditions in
[*] * concurrent programs) and the <allocation_strategy_> (which
[*] * determines what memory pool is used to allocate the memory).
[*] */
[*]class ACE_Export ACE_Data_Block
[*]{
[*]public:
[*]// = Initialization and termination methods.
[*]/// Default "do-nothing" constructor.
[*]ACE_Data_Block (void);
[*]
[*]/// Initialize.
[*]ACE_Data_Block (size_t size,
[*]                  ACE_Message_Block::ACE_Message_Type msg_type,
[*]                  const char *msg_data,
[*]                  ACE_Allocator *allocator_strategy,
[*]                  ACE_Lock *locking_strategy,
[*]                  ACE_Message_Block::Message_Flags flags,
[*]                  ACE_Allocator *data_block_allocator);
[*]
[*]/// Delete all the resources held in the message.
[*]virtual ~ACE_Data_Block (void);
[*]
[*]/// Get type of the message.
[*]ACE_Message_Block::ACE_Message_Type msg_type (void) const;
[*]
[*]/// Set type of the message.
[*]void msg_type (ACE_Message_Block::ACE_Message_Type type);
[*]
[*]/// Get message data pointer
[*]char *base (void) const;
[*]
[*]/// Set message data pointer (doesn't reallocate).
[*]void base (char *data,
[*]             size_t size,
[*]             ACE_Message_Block::Message_Flags mflags = ACE_Message_Block::DONT_DELETE);
[*]
[*]/// Return a pointer to 1 past the end of the allocated data in a message.
[*]char *end (void) const;
[*]
[*]/**
[*]   * Return a pointer to 1 past the end of the allotted data in a message.
[*]   * The allotted data may be less than allocated data if <size()> is passed
[*]   * an argument less than <capacity()>.
[*]   */
[*]char *mark (void) const;
[*]
[*]// = Message size is the total amount of space allotred.
[*]
[*]/// Get the total amount of allotted space in the message.The amount of
[*]/// allotted space may be less than allocated space.
[*]size_t size (void) const;
[*]
[*]/// Set the total amount of space in the message.Returns 0 if
[*]/// successful, else -1.
[*]int size (size_t length);
[*]
[*]/// Get the total amount of allocated space.
[*]size_t capacity (void) const;
[*]
[*]/**
[*]   * Return an exact "deep copy" of the message, i.e., create fresh
[*]   * new copies of all the Data_Blocks and continuations.
[*]   * Notice that Data_Blocks can act as "Prototypes", i.e. derived
[*]   * classes can override this method and create instances of
[*]   * themselves.
[*]   */
[*]virtual ACE_Data_Block *clone (ACE_Message_Block::Message_Flags mask = 0) const;
[*]
[*]/**
[*]   * As clone above, but it does not copy the contents of the buffer,
[*]   * i.e., create a new Data_Block of the same dynamic type, with the
[*]   * same allocator, locking_strategy, and with the same amount of
[*]   * storage available (if @a max_size is zero) but the buffer is unitialized.
[*]   * If @a max_size is specified other than zero, it will be used when
[*]   * creating the new data block.
[*]   */
[*]virtual ACE_Data_Block *clone_nocopy (ACE_Message_Block::Message_Flags mask = 0,
[*]                                        size_t max_size = 0) const;
[*]
[*]/// Return a "shallow" copy that increments our reference count by 1.
[*]ACE_Data_Block *duplicate (void);
[*]
[*]/**
[*]   * Decrease the shared reference count by 1.If the reference count
[*]   * is > 0 then return this; else if reference count == 0 then delete
[*]   * @c this and @a mb and return 0.Behavior is undefined if reference
[*]   * count < 0.
[*]   */
[*]<span style="font-size:18px;"><strong>ACE_Data_Block *release (ACE_Lock *lock = 0);</strong>
[*]</span>
[*]// = Message flag accessors and mutators.
[*]/// Bitwise-or the @a more_flags into the existing message flags and
[*]/// return the new value.
[*]ACE_Message_Block::Message_Flags set_flags (ACE_Message_Block::Message_Flags more_flags);
[*]
[*]/// Clear the message flag bits specified in @a less_flags and return
[*]/// the new value.
[*]ACE_Message_Block::Message_Flags clr_flags (ACE_Message_Block::Message_Flags less_flags);
[*]
[*]/// Get the current message flags.
[*]ACE_Message_Block::Message_Flags flags (void) const;
[*]
[*]/// Obtain the allocator strategy.
[*]ACE_Allocator *allocator_strategy (void) const;
[*]
[*]// = The locking strategy prevents race conditions.
[*]/// Get the locking strategy.
[*]ACE_Lock *locking_strategy (void);
[*]
[*]/// Set a new locking strategy and return the hold one.
[*]ACE_Lock *locking_strategy (ACE_Lock *);
[*]
[*]/// Dump the state of an object.
[*] <span style="font-size:24px;"><strong> void dump (void) const;</strong>
[*]</span>
[*]/// Get the current reference count.
[*]int reference_count (void) const;
[*]
[*]/// Get the allocator used to create this object
[*]ACE_Allocator *data_block_allocator (void) const;
[*]
[*]protected:
[*]/// Internal release implementation
[*]virtual ACE_Data_Block *release_i (void);
[*]
[*]/// Internal get the current reference count.
[*]int reference_count_i (void) const;
[*]
[*]/**
[*]   * Decrease the reference count, but don't delete the object.
[*]   * Returns 0 if the object should be removed.
[*]   * If @a lock is equal to the locking strategy then we assume that
[*]   * the lock is being held by the current thread; this is used to
[*]   * release all the data blocks in a chain while holding a single
[*]   * lock.
[*]   */
[*]friend class ACE_Message_Block;
[*]ACE_Data_Block *release_no_delete (ACE_Lock *lock);
[*]
[*]/// Type of message.
[*]ACE_Message_Block::ACE_Message_Type type_;
[*]
[*]/// Current size of message block.
[*]size_t cur_size_;
[*]
[*]/// Total size of buffer.
[*]size_t max_size_;
[*]
[*]/// Misc flags (e.g., DONT_DELETE and USER_FLAGS).
[*]ACE_Message_Block::Message_Flags flags_;
[*]
[*]/// Pointer To beginning of message payload.
[*]char *base_;
[*]
[*]// = Strategies.
[*]/**
[*]   * Pointer to the allocator defined for this ACE_Data_Block.Note
[*]   * that this pointer is shared by all owners of this
[*]   * ACE_Data_Block.
[*]   */
[*]ACE_Allocator *allocator_strategy_;
[*]
[*]/**
[*]   * Pointer to the locking strategy defined for this
[*]   * ACE_Data_Block.This is used to protect regions of code that
[*]   * access shared ACE_Data_Block state.Note that this lock is
[*]   * shared by all owners of the ACE_Data_Block's data.
[*]   */
[*]ACE_Lock *locking_strategy_;
[*]
[*]/**
[*]   * Reference count for this ACE_Data_Block, which is used to avoid
[*]   * deep copies (i.e., clone()).Note that this pointer value is
[*]   * shared by all owners of the <Data_Block>'s data, i.e., all the
[*]   * ACE_Message_Blocks.
[*]   */
[*]int reference_count_;
[*]
[*]/// The allocator use to destroy ourselves.
[*]ACE_Allocator *data_block_allocator_;
[*]
[*]private:
[*]// = Disallow these operations.
[*]ACE_Data_Block &operator= (const ACE_Data_Block &);
[*]ACE_Data_Block (const ACE_Data_Block &);
[*]};
[*]
[*]ACE_END_VERSIONED_NAMESPACE_DECL
[*]
[*]#if defined (__ACE_INLINE__)
[*]#include "ace/Message_Block.inl"
[*]#endif /* __ACE_INLINE__ */
[*]
[*]#include "ace/Message_Block_T.h"
[*]
[*]#include /**/ "ace/post.h"
[*]
[*]#endif /* ACE_MESSAGE_BLOCK_H */

以上均就是所有的方法了
下面也就是分析容易混淆的函数ACE_Message_Block中有多个获取大小或者长度的函数,容易混淆.
下图是根据ACE_Message_Block(实际是ACE_Data_Block)空间的处理状况所绘,能比较清晰的反应出它们的异同.
需要注意,为了表现出多样性,下图是wr_ptr(),rd_ptr(),size()都调用过之后的情景.
红色表示是ACE_Message_Block独有的函数, 其余则ACE_Message_Block和ACE_Data_Block均有.
矩形纸上函数的返回值均为指针类型,之下的返回值均为size_t类型.

函数说明
length()有效数据的长度== wr_ptr() – rd_ptr()
size()全部可用空间的长度,如果没有size()而变小,则等同capacity()== mark() – base()
space()剩余可用空间的长度<= size() - length(),因为不含rd_ptr()移动过的空间== mark() – wr_ptr()
capacity()最大空间的长度(ACE_Message_Block构造或初始化时所用参数值)== end() – base()
total_length()复合消息(ACE_Message_Block内单向链 cont())的总长度
total_size()复合消息(ACE_Message_Block内单向链 cont())的总大小
total_capacity()复合消息(ACE_Message_Block内单向链 cont())的总空间大小

duplicate()浅拷贝函数,公用一个内部的ACE_Data_Block
ACE_Message_Block::duplicate() 与 ACE_Data_Block.duplicate()的实现是不同的.
ACE_Data_Block::duplicate()简单的只是将自身的reference加+1, 然后返回自身(this)
ACE_Message_Block:duplicate()则将自身copy了一份, 然后将自身的状态值赋给拷贝,注意它们公用同一个data_block.而且ACE_Message_Block::duplicate()支持复合消息,它会检查内部单向链,来依次调用其duplicate().ACE_Message_Block::clone()深拷贝, 不但拷贝自身,内部的ACE_Data_Block也一并拷贝了,并且支持复合消息.ACE_Data_Block.size(size_t len)函数, 动态的变化ACE_Data_Block持有的空间.
ACE_Message_Block.size(size_t len)函数是ACE_Data_Block.size(size_t len)的简单包裹.
如果len比现有的尺寸小, 简单的cur_size_ = length;
如果len比现有的尺寸大, 会申请新的空间并拷贝原所有数据.注意! 这里可能会发生空间控制权的转换! 即标志位DONT_DELETE的变化.若原ACE_Data_Block使用托管空间, 则此时会更替为自己申请的空间,从而拥有了控制权, 所以此时要注意原有空间的管理.
对ACE_Message_Block和ACE_Data_Block, 除非主动调用size(), 否则它们不会自动申请和扩大空间.ACE_Message_Block::crunch() 将现有数据移动到现有的缓冲的开始.ACE_Message_Block::reset()将现有读写指针赋为初始值(ACE_Data_Block.base())ACE_Message_Block::base()是对ACE_Data_Block.base()的简单包裹1)ACE_Message_Block的构造函数中,如果data为NULL, 则ACE_Message_Block会为其自动分配空间. 但如data非NULL,则ACE_Message_Block会直接引用data指向的空间, 并不会进行新的空间分配和拷贝.所以需要特别注意, 在ACE_Message_Block的实例没有销毁之前,不能释放data指向的空间. 2)虽然ACE_Message_Block会根据size的值来更改自己的size(),但wr_ptr不会根据data的长度进行设置, 造成length()的返回为0.需要特别注意, 当构造一个ACE_Message_Block实例后, 随之需要追加数据时,必须设置wr_ptr的值,否则原有数据将会被覆写.此时的含义是: ACE_Message_Block代管了data缓冲区,但不负责缓冲区的空间管理(因为也不是由它申请的).默认定义的flag: enum { DONT_DELETE = 01, USER_FLAGS = 0x1000 } 1) set_flags()、clr_flags()是对ACE_Message_Block中的数据指针(ACE_Data_Block*)进行设置.2) set_self_flags(),clr_self_flags()是对ACE_Message_Block本身进行设置.ACE_Message_Block::copy(const char* buf) 函数将字符串copy到ACE_Message_Block, 如果内在空间不足, 将会返回-1.需要特别注意, copy的数据将包括末尾的0, 也就是copy的数据长度为strlen(buf)+1.而且, 会自动进行wr_ptr()的设置ACE_Data_Block的析构函数是释放持有空间base_的惟一路径(size()的情况不讨论).ACE_Data_Block中通过duplicate()递增引用计数. ACE_Data_Block中通过release()递减引用计数, 当引用计数为0时,先调用ACE_Data_Block析构函数,然后释放ACE_Data_Block自身.
注意, ACE_Data_Block的构造和析构函数都不知道引用计数的存在. 在构造函数中, 只是设置了初始值1.ACE_Data_Block一个很奇怪的地方就是ACE_Data_Block::duplicate()的实现, 并没有创建新的拷贝, 而仅仅是返回了自身(return this). 这中实现方式带来了很多奇怪的问题.如下面的2,3.
release()-> release_no_delete()->release_i()->~ACE_Data_Block()如果在Stack上构造ACE_Data_Block,那么不能使用release()函数, 因为release()函数会试图删除this如果在stack上构造ACE_Data_Block, 那么不能使用duplicate()函数, 因为duplicate()返回的是this指针, 栈中的ACE_Data_Block析构后会导致问题.如果在heap上构造ACE_Data_Block,那么尽量使用release()来替代delete, 如果存在因为析构并不处理reference count, delete时不考虑其它会导致指针悬空.

更多文章,欢迎访问:http://blog.csdn.net/wallwind

此间足迹 发表于 2012-3-14 21:36:35

支持下辛苦了楼主
页: [1]
查看完整版本: ACE_Message_Block-----ACE消息的存储