找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 8684|回复: 4

ACE_Message_Block中的locking_strategy的使用

[复制链接]
发表于 2007-12-27 23:31:30 | 显示全部楼层 |阅读模式
作者:海阔天空

    接着上一次的写。
    先我们看看Ace_Message_Block中的locking_strategy锁到底作用在什么地方。
    通过查看ACE的源代码,我们可以发现,在Ace_Message_Block中根本没有保存这把锁,而是直接传入内部的ACE_Data_Block中。在ACE_Data_Block中,保存了这把锁。ACE_Data_Block使用这把锁来控制duplicate和release时的同步。
    可以这么说,如果你的程序中没有使用duplicate,那么,你在构造Ace_Message_Block的时候完全可以不用传递这个值,但如果你使用了duplicate,那么请一定加上这把锁。
    由上面分析,我们可以认为,一个ACE_Data_Block对应着一把锁。实际上也应该这样理解,但是,ACE的作者却不是这么用的。
    请看Ace_Message_Block的release和release_i()函数:
  1. ACE_Message_Block * ACE_Message_Block::release (void)
  2. ACE_Message_Block * ACE_Message_Block::release (void)
  3. {
  4.   ACE_TRACE ("ACE_Message_Block::release");
  5.   // We want to hold the data block in a temporary variable because we
  6.   // invoked "delete this;" at some point, so using this->data_block_
  7.   // could be a bad idea.
  8.   ACE_Data_Block *tmp = this->data_block ();
  9.   // This flag is set to 1 when we have to destroy the data_block
  10.   int destroy_dblock = 0;
  11.   ACE_Lock *lock = 0;
  12.   // Do we have a valid data block
  13.   if (this->data_block ())
  14.     {
  15.       // Grab the lock that belongs to my data block
  16.       lock = this->data_block ()->locking_strategy ();
  17.       // if we have a lock
  18.       if (lock != 0)
  19.         {
  20.           // One guard for all
  21.           ACE_GUARD_RETURN (ACE_Lock, ace_mon, *lock, 0);
  22.           // Call non-guarded release with <lock>
  23.           destroy_dblock = this->release_i (lock);
  24.         }
  25.       // This is the case when we have a valid data block but no lock
  26.       else
  27.         // Call non-guarded release with no lock
  28.         destroy_dblock = this->release_i (0);
  29.     }
  30.   else
  31.     // This is the case when we don't even have a valid data block
  32.     destroy_dblock = this->release_i (0);
  33.   if (destroy_dblock != 0)
  34.     {
  35.       ACE_Allocator *allocator = tmp->data_block_allocator ();
  36.       ACE_DES_FREE (tmp,
  37.                     allocator->free,
  38.                     ACE_Data_Block);
  39.     }
  40.   return 0;
  41. }
  42. int ACE_Message_Block::release_i (ACE_Lock *lock)
  43. {
  44.   ACE_TRACE ("ACE_Message_Block::release_i");
  45.   // Free up all the continuation messages.
  46.   if (this->cont_)
  47.     {
  48.       ACE_Message_Block *mb = this->cont_;
  49.       ACE_Message_Block *tmp = 0;
  50.       do
  51.         {
  52.           tmp = mb;
  53.           mb = mb->cont_;
  54.           tmp->cont_ = 0;
  55.           ACE_Data_Block *db = tmp->data_block ();
  56.           if (tmp->release_i (lock) != 0)
  57.             {
  58.               ACE_Allocator *allocator = db->data_block_allocator ();
  59.               ACE_DES_FREE (db,
  60.                             allocator->free,
  61.                             ACE_Data_Block);
  62.             }
  63.         }
  64.       while (mb);
  65.       this->cont_ = 0;
  66.     }
  67.   int result = 0;
  68.   if (ACE_BIT_DISABLED (this->flags_,
  69.                         ACE_Message_Block::DONT_DELETE) &&
  70.       this->data_block ())
  71.     {
  72.       if (this->data_block ()->release_no_delete (lock) == 0)
  73.         result = 1;
  74.       this->data_block_ = 0;
  75.     }
  76.   // We will now commit suicide: this object *must* have come from the
  77.   // allocator given.
  78.   if (this->message_block_allocator_ == 0)
  79.     delete this;
  80.   else
  81.     {
  82.       ACE_Allocator *allocator = this->message_block_allocator_;
  83.       ACE_DES_FREE (this,
  84.                     allocator->free,
  85.                     ACE_Message_Block);
  86.     }
  87.   return result;
  88. }
复制代码
看出什么问题来了不?
如果你有两个或者两个以上的Message_Block用cont()连接起来。在调用release时,ACE会用第一的Message_Block的锁去释放后面的Message_Block。这样,如果这几个Message_Block不时用的同一把锁的话,在Release的时候就会出错。
分析了上面的问题,现在我们讨论一下Message-Block的优化。
首先.ACE_Data_Block中的锁的优化。
        很多人使用的时候都是传入的一把锁给所有的ACE_Data_Block,结果每一个ACE_Message_Block,在duplicate 或者release的时候都需要获取这把锁。优化的方案就是为ACE_Data_Block都传一把锁进去,当然,在Release的时候就必须注意,不要直接调用ACE_Message_Block的Release函数。
其次ACE_Allocator的优化。
        ACE_Allocator中有一把锁用于维持链表的线程安全。当你整个应用程序就只有一个ACE_Allocator时,每一个池中的对象在分配或者释放的时候都需要获取这把锁,那么线程之间的碰撞时很激烈的,解决的办法也很简单。在程序中每一个ACE_Allocator不要太大,相当于再做一个ACE_Allocator的池。
 楼主| 发表于 2007-12-27 23:31:39 | 显示全部楼层
想问版主一个问题,如果牵涉到多结构体链表(或者数组)的传输,这样的锁会不会增加延迟呢?

比如说我设定一个内存区,当传输了800个相同结构体的数据时就将这些数据放到一个LIST对象模板中.这期间可能会收到其它程序发来的其它表结构体(帧头有表结构体类型标识)的数据,我只能暂存.这时如果使用Message_Block的话在锁的控制方面是不是和例子中一样呢?
 楼主| 发表于 2007-12-27 23:31:46 | 显示全部楼层
文章是我转贴的,但其实只是提供了一个管理思路,我并不同意他的意见,因为这样违背了ACE_Message_Block的设计本意,如果不能方便的调用release(),会导致很多不便,甚至ACE内部框架都可能无法运行,因为很多框架之间都是用ACE_Message_Block粘合的。
要说对性能的影响,得看情况,如果你选择的锁策略是轻量级的,能够重入,而且对已经获得锁的线程的再次进入,不会造成问题,我认为其实不必考虑这个消耗,甚至可以把锁设置为NULL策略.
如果你采用的锁策略太重,就对性能有影响了。
看你的实际需要吧。
 楼主| 发表于 2007-12-27 23:31:54 | 显示全部楼层
感觉这个锁用起来比校麻烦,因为常用的ACE_Thread_Mutex等都不是从其继承而来,所以得通过下面的方式转化来用

ACE_Lock_Adapter<ACE_Thread_Mutex> locker_;

还有切记上面的一句话 “ACE_Data_Block使用这把锁来控制duplicate和release时的同步”,这是有血的教训的
发表于 2013-4-19 09:41:09 | 显示全部楼层
麻烦楼主讲一下这个locking_strategy怎么使用,给个使用例子吧
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-12-22 16:25 , Processed in 0.020061 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表