关于ACE_Task::last_thread()
在ACE应用中,我们经常用ACE_Task类实现多线程处理。由于ACE_Svc_Handler从ACE_Task派生,当你写的应用程序使用了Acceptor-Connector框架同时又直接使用ACE_Task,如线程池,这时你会使用到ACE_Task。
因为许多ACE_Task对应是动态分配的,所以,必须在不再需要时把它们正确地释放掉,知道何时可以释放对象,这一点非常重要。C++NPv2第189页描述了当多线程涉及到的task对象在它们退出时,使用ACE_Task::thr_count()方法确定正确释放它们的方法。
在C++NPv2文档中描述的过程并不不安全,这里有一个用例可以说明这一点。原因如下:
ACE在调用ACE_Task::close()挂钩(hook)函数前检查线程计数。
线程锁(task thread)使控制线程计数顺序化,所以不能通过调用ACE_Task::close()达到控制线程数这一目的,这是因为关闭挂勾(close hook)方法会删除task 对象。因此,多个线程检查ACE_Task:: thr_count()的值都为0是可能存在的。
举例来说吧,我们假设这里有两个线程,A和B,这给都要退出。线程A从svc()方法中退出控制,同时,ACE开始线程记录保护(record-keeping)。ACE获得线程锁并把活动线程数从2减为1,接着,ACE释放线程锁并调用task的close()挂钩方法。其间,线程B也从svc()方法中退出。在线程A检查ACE_Task::thr_count()之前,ACE已执行线程B的清楚操作可能导致task的线程计数器从1变为0.如果那样,线程A和B都会看到线程计数器为0,并都试图清理task对象。这一点肯定不是好事.......
发现并指出这一问题是一位长时间使用ACE的用户,Howard Finer,经过一些迭代和试验Howard找到一个解决这一问题的办法,即额外的维护线程计数器,记住到底是哪一个线程真实的把线程计数器从1变为0,(上述例子中的线程B)。这就要求ACE_Task增加一个新的方法 :
ACE_thread_t ACE_Task::last_thread (void) const
所以,在你的代码实现ACE_Task::close()时需要包含如下的检查
if (ACE_OS::thr_equal (ACE_Thread::self (),
this->last_thread ()))
{
// Do the cleanup here...
}
这个方法可能会出现在ACE 5.5.2中。