消息队列的使用已经在前面的ACE_Semaphore中使用到了,其中使用的就是它的典型用法。
ACE_Message_Queue
/**
* @class ACE_Message_Queue
*
* @brief A message queueing facility with parameterized synchronization
* capability. ACE_Message_Queue is modeled after the queueing facilities
* in System V STREAMs.
*
* ACE_Message_Queue is the primary queueing facility for
* messages in the ACE framework. It's one template argument parameterizes
* the queue's synchronization. The argument specifies a synchronization
* strategy. The two main strategies available for ACE_SYNCH_DECL are:
* -# ACE_MT_SYNCH: all operations are thread-safe
* -# ACE_NULL_SYNCH: no synchronization and no locking overhead
*
* All data passing through ACE_Message_Queue is in the form of
* ACE_Message_Block objects. @sa ACE_Message_Block.
*/
ACE_Message_Queue的模型是仿照System V streams提供的排队设施设计的,但是与System V排队设施不同,使用ACE的排队设施,可以在单个进程中进行高效的线程间通信,但是没有提供用于进程间通信的排队设施。
为了实现线程安全,经常要实现多种版本的库,多线程库、单线程库,这样会给库的维护与开发带来很多问题,而在ACE中经常看到ACE_<ACE_XXX>这种用法,ACE_XXX类代表的是一系列的宏定义,这些宏决定了使用哪种策略。例如消息队列的使用要public ACE_Task<ACE_MT_SYNCH>而参数ACE_MT_SYNCH的定义如下:
class ACE_Export ACE_MT_SYNCH
{
public:
typedef ACE_Thread_Mutex MUTEX;
typedef ACE_Null_Mutex NULL_MUTEX;
typedef ACE_Process_Mutex PROCESS_MUTEX;
typedef ACE_Recursive_Thread_Mutex RECURSIVE_MUTEX;
typedef ACE_RW_Thread_Mutex RW_MUTEX;
typedef ACE_Condition_Thread_Mutex CONDITION;
typedef ACE_Condition_Recursive_Thread_Mutex RECURSIVE_CONDITION;
typedef ACE_Thread_Semaphore SEMAPHORE;
typedef ACE_Null_Semaphore NULL_SEMAPHORE;
};
可以对比下另外一个参数ACE_NULL_SYNCH
class ACE_Export ACE_NULL_SYNCH
{
public:
typedef ACE_Null_Mutex MUTEX;
typedef ACE_Null_Mutex NULL_MUTEX;
typedef ACE_Null_Mutex PROCESS_MUTEX;
typedef ACE_Null_Mutex RECURSIVE_MUTEX;
typedef ACE_Null_Mutex RW_MUTEX;
typedef ACE_Null_Condition CONDITION;
typedef ACE_Null_Condition RECURSIVE_CONDITION;
typedef ACE_Null_Semaphore SEMAPHORE;
typedef ACE_Null_Mutex NULL_SEMAPHORE;
};
简单比较下第一个宏MUTEX的定义,在MT_SYNCH(多线程同步)里面为ACE_Thread_Mutex 而在NULL_SYNCH(单线程同步)里面为ACE_Null_Mutex,而ACE_NULL_Mutex是一个“方法都没有实现的互斥锁”,ACE_NULL_Mutex与ACE_Thread_Mutex 有相同的接口,但是没有实现任何方法,所以使用起来接口一样,但效果不一样。这样就把一个类ACE_MT_SYNCH作为参数,从而决定了ACE_Task的消息队列的实现,从而简化了库的设计。ACE中大量这样的用法,依照具体的的类型产生相应的模板或者模板函数,通过模板参数实现根据环境需要改变其行为方式,通过静态绑定来进一步提高效率。这种策略叫做traits策略,与strategy有很大不同:traits 策略的替换是在编译时确定的,strategy是通过动态绑定实现的。
消息块是消息队列中的固定的对象结构,可以把消息块当成一种高级的数据缓存区,支持引用计数和数据共享,每个消息块都含有两个指针:rd_ptr()和指向要读取的下一个字节:wr_ptr()。一旦使用完了消息块,要用release()方法释放它,从而使引用计数减一,当计数到达0的时候,ACE会自动释放分配的内存。消息块还有一个类型字段,可以通过msg_type()修改设置,还提供了一个duplicate()方法,用以创建一个新的指向块的数据的引用,并使引用计数加一,另外还提供了clone()方法,用以创建消息块的深度拷贝。
/**
* @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.
*/
// message_block.cpp #include "ace/Task.h" int ACE_TMAIN(int, ACE_TCHAR *[]) { //use copy ACE_Message_Block *mb; ACE_NEW_RETURN(mb, ACE_Message_Block(128), -1); const char *deviceAddr = "Dev#12"; mb->copy(deviceAddr, ACE_OS::strlen(deviceAddr) + 1); ACE_DEBUG((LM_DEBUG, ACE_TEXT("Devide addr -->%s\n"), mb->rd_ptr())); //use wr_ptr() ACE_Message_Block *mb2; ACE_NEW_RETURN(mb2, ACE_Message_Block(128), -1); const char *commandSeq = "commandSeq#14"; ACE_OS::sprintf(mb2->wr_ptr(), commandSeq); //move the wr_ptr() forward in the buffer by the amount of data we put in. mb2->wr_ptr(ACE_OS::strlen(commandSeq)+1); ACE_DEBUG((LM_DEBUG, ACE_TEXT("Command Sequence -->%s\n"), mb2->rd_ptr())); //the rd_ptr() also need forward mb2->rd_ptr(ACE_OS::strlen(mb2->rd_ptr())+1); mb2->release(); //the use of msg_type() //send a hangup notification to the receiver. ACE_NEW_RETURN(mb2, ACE_Message_Block(128, ACE_Message_Block::MB_HANGUP), -1); //send an error notification to the receiver. mb2->msg_type(ACE_Message_Block::MB_ERROR); return 0; }
《C++NPv1》
http://jnn.blogbus.com/logs/180955.html