概览:
详解:
通过cpp network programming volume2 中的该图可以简单看出ACE_Message_Queue, ACE_Message_Block, 以及ACE_Data_Block的关系;下面主要讲解使用这些类的过程中需要注意的问题,
实例:(windows+vs2010)
#include "stdafx.h"
#include "ace/Message_Block.h"
#include "ace/Thread_Mutex.h"
#include "ace/Lock_Adapter_T.h"
#include "ace/Condition_Thread_Mutex.h"
#include "ace/Message_Queue_T.h"
#include "ace/Synch_Traits.h"
#include <stdio.h>
#pragma comment(lib, "ACEd.lib")
//message_block default allocator ACE_New_Allocator.
#define MESSAGE_DEFAULT_BUFFER_SIZE 1024
int
ACE_TMAIN (int argc, ACE_TCHAR *argv[])
{
ACE_Thread_Mutex *pThreadMutex;
ACE_NEW_RETURN(pThreadMutex, ACE_Thread_Mutex, -1);
if( pThreadMutex == (void *)-1 )
{
fprintf(stderr, "pThreadMutex allocation failed.\n" );
}
ACE_Lock_Adapter<ACE_Thread_Mutex> lock(*pThreadMutex);
ACE_Message_Block *pmb = ::new ACE_Message_Block(
MESSAGE_DEFAULT_BUFFER_SIZE,
ACE_Message_Block::MB_DATA,
0,
0,
0,
&lock);
pmb->copy("I am testing, I am testing, I am testing, I am testing, I am testing, I am testing, I am testing");
ACE_Message_Block *pmb1 = ::new ACE_Message_Block(MESSAGE_DEFAULT_BUFFER_SIZE);
pmb1->copy("i am mb1, i am mb1, i am mb1, i am mb1, i am mb1, i am mb1, i am mb1, i am mb1, i am mb1");
ACE_Message_Block *pmb2 = ::new ACE_Message_Block(MESSAGE_DEFAULT_BUFFER_SIZE);
pmb2->copy("i am mb2, i am mb2,i am mb2,i am mb2,i am mb2,i am mb2,i am mb2,i am mb2,i am mb2,i am mb2");
ACE_Message_Queue<ACE_MT_SYNCH> mq;
mq.enqueue( pmb);
mq.enqueue( pmb1);
mq.enqueue( pmb2 );
ACE_Message_Queue_Iterator<ACE_MT_SYNCH> mqIter(mq);
ACE_Message_Block *pBlock = NULL;
for( ; mqIter.next(pBlock) ; mqIter.advance() )
{
fprintf(stdout, "%s\n", pBlock->rd_ptr() );
}
//delete pThreadMutex;
getchar();
return 0;
}
@注意事项:
@1 在使用ACE_Messag_Block定义的对象指针必须能够被delete,无论该内存是通过堆或者栈分配出来再构造亦或直接new分配构造。
@2 上述实例中的pThreadMutex一定不能被提前delete掉,因为在ACE_Message_Queue在析构时,会调用内部所有的ACE_Message_Block的release方法,代码:
template <ACE_SYNCH_DECL> int
ACE_Message_Queue<ACE_SYNCH_USE>::flush_i (void)
{
int number_flushed = 0;
// Remove all the <ACE_Message_Block>s in the <ACE_Message_Queue>
// and <release> their memory.
for (this->tail_ = 0; this->head_ != 0; )
{
++number_flushed;
size_t mb_bytes = 0;
size_t mb_length = 0;
this->head_->total_size_and_length (mb_bytes,
mb_length);
// Subtract off all of the bytes associated with this message.
this->cur_bytes_ -= mb_bytes;
this->cur_length_ -= mb_length;
--this->cur_count_;
ACE_Message_Block *temp = this->head_;
this->head_ = this->head_->next ();
// Make sure to use <release> rather than <delete> since this is
// reference counted.
temp->release ();
}
#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1)
// The monitor should output only if the size has actually changed.
if (number_flushed > 0)
{
this->monitor_->receive (this->cur_length_);
}
#endif
return number_flushed;
}
而release方法中使用了出入的ACE_Lock对象指针,代码如下:
// Grab the lock that belongs to my data block
lock = this->data_block ()->locking_strategy ();
// if we have a lock
if (lock != 0)
{
// One guard for all
ACE_GUARD_RETURN (ACE_Lock, ace_mon, *lock, 0);
// Call non-guarded release with @a lock
destroy_dblock = this->release_i (lock);
}
所以要想掌握析构的顺序,最好将ACE_Message_Queue也能支持delete操作符。
@3 ACE_Message_Block中内聚了ACE_Data_Block对象指针,ACE_Data_Block中内存的分配默认使用ACE_New_Allocator。ACE中的Allocators种类有:
所以自己也可以定义Allocator作为ACE_Message_Block的参数传入。
@4 在ACE_Message_Queue中有三个参数,前两个代表高水位和低水位,高水位主要是指enqueue的ACE_Message_Block的最大字节数总和,低水位代表在dequeue时,如果发现自己数低于低水位,那么通知等待enqueue的线程可以继续了。
@5 ACE也提供了ACE_Message_Queue_Ex供我们选择队列中存放的类型,
template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL>
class ACE_Message_Queue_Ex