分类: cACE_Message_Block是ACE中一个很核心的基础类,应用非常广泛,所以需要花点心思去研究。学习的过程有几点心得体会记录下吧。
创建消息的这四点引自http://hi.baidu.com/zoupng/blog/item/562290878b31c52ec75cc35c.html。
1、直接给消息块分配内存空间创建。
ACE_Message_Block *mb = new ACE_Message_Block (30);
2、共享底层数据块创建。
char buffer[100];
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()方法实际地创建整个消息块的新副本,包括它的数据块和附加部分;也就是说,这是一次"深拷贝"。
(第五点引自http://blog.csdn.net/ydogg/archive/2007/10/10/1818949.aspx)
5、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时不考虑其它会导致指针悬空。
理解ACE_Message_Block是用ACE_Data_Block来保存数据的,这一点很关键。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ydogg/archive/2007/10/10/1818949.aspx
补充点吧:
1、ACE_Message_Block的几个大小,让人头晕,下面这张图非常清晰地显示了它们的计算方法,如果使用wr_ptr往消息中写了数据,如果自己不挪动指针的话,length的大小是不会改变的,length的大小等于wr_ptr指针的位置减去rd_ptr的位置。
2、使用cont方法可以将消息简单地连接起来,比使用消息队列要简单。
给出一段示例代码吧,这里没有涉及消息的到期时间和执行之间等,这些特性需要结合动态队列来学习使用。
ACE_Message_Block* mb = new ACE_Message_Block(30);
ACE_DEBUG((LM_DEBUG, "capacity : %d, length : %d, space : %dn", mb->capacity(), mb->length(), mb->space()));
//获得写指针
char* ptr = mb->wr_ptr();
//将数据写入消息中
ACE_OS::memcpy(ptr, "fzjfzjfzj", 3);
//挪动写指针
mb->wr_ptr(9);
//测试下引用计数,duplicate是浅拷贝,这样mb2和mb就指向同一个消息了
ACE_Message_Block *mb2 = mb->duplicate();
//clone是深度拷贝,不会增加引用计数
ACE_Message_Block *mb3 = mb->clone();
//释放下试试
//mb2->release();
//将读指针往前挪动四个位置会导致length=5
//mb->rd_ptr(4);
ACE_DEBUG((LM_DEBUG, "capacity : %d, length : %d, space : %d, reference_count : %dn", mb->capacity(), mb->length(), mb->space(), mb->reference_count()));
//再构造一个消息,用于和mb串联起来
ACE_Message_Block* mb4 = new ACE_Message_Block(30);
ptr = mb4->wr_ptr();
ACE_OS::memcpy(ptr, "wxy", 3);
//将mb和mb4串联起来
mb->cont(mb4);
//我期待这样导致循环链表,结果是程序卡死不动了,这里需要分析下cont的源代码
//mb4->cont(mb);
ACE_Message_Block* pMessageBlock = mb;
//遍历消息
for(; pMessageBlock != NULL; pMessageBlock = mb->cont())
{
//注意这个total_capacity的值哦
ACE_DEBUG((LM_DEBUG, "data: %s, total_length: %dn", pMessageBlock->rd_ptr(), pMessageBlock->total_capacity()));
mb = pMessageBlock;
}
//在栈中构造一个消息,调用其release方法会导致断言失败
//这是因为使用delete释放栈空间
//ACE_Message_Block mb5 (30);
//ptr = mb5.wr_ptr();
//ACE_OS::memcpy(ptr, "wyy", 3);
//mb5.release();
//使用copy的时候需要注意每次copy之后会在字符串后面添加一个''
//下面的例子会存入"helloworld"
ACE_Message_Block mb6 (30);
mb6.copy("hello");
mb6.copy("world");
//如果这样做的话就只会hello了
//mb6.copy("helloworld");