ACE_Recursive_Thread_Mutex 的设计目的是为了避免代码中某个线程自己递归对互斥体进行申请而变成死锁的情况
但通过对其介绍文章的阅读 (参考<C++网络编程卷1> 10.6 ACE条件变量类) 发现实现上也可能会因为线程间的竞争ACE_Thread_Mutex 和 ACE_Condition_Thread_Mutex 2个不同资源时形成互锁,代码如下
int ACE_Recursive_Thread_Mutex::acquire()
{
ACE_thread_t t_id = ACE_OS::thr_self();
ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, lock_, -1);
if(nesting_level_ == 0){
owner_id_ = t_id;
nesting_level_ = 1;
}
else if(t_id == owner_id_)
nesting_level_ ++;
else{
while( nesting_level_ > 0)
lock_available_.wait();
owner_id_ = t_id;
nesting_level_ = 1;
}
return 0;
}
在申请递归互斥体的操作上,acquire 先确定调用线程的id ,然后通过scoped locking 技术得到 ACE_Thread_Mutex lock_ 从而得以串行化访问nesting_level_和owner_id_,
ACE_Condition_Thread_Mutex lock_available_ 条件变量实际为真正用来挂起 非所有者线程 ,这些挂起线程需要等待嵌套计数 nesting_level_ 被占用线程降至0且互斥体被释放
出问题的代码在于lock_available_.wai()t前已经通过Ace_Guard 将 lock_ 给占用了, 而其等待的lock_available_.signal() 却需要先取得lock_,代码如下
int ACE_Recursive_Thread_Mutex::release()
{
owner_id_ = 0;
ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, lock_, -1);
nesting_level_ --;
if(nesting_level_ == 0)
lock_available_.signal();
return 0;
}
理想的修改方式是在 lock_available_.wait() 一句前先释放自己占用的 资源 guard.release() 然后再lock_available_.wait() 返回后 再次 guard.acquire() 下。像这样
int ACE_Recursive_Thread_Mutex::acquire()
{
ACE_thread_t t_id = ACE_OS::thr_self();
ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, lock_, -1);
if(nesting_level_ == 0){
owner_id_ = t_id;
nesting_level_ = 1;
}
else if(t_id == owner_id_)
nesting_level_ ++;
else{
while( nesting_level_ > 0)
{
guard.release();
lock_available_.wait();
guard.acquire();
}
owner_id_ = t_id;
nesting_level_ = 1;
}
return 0;
}
---------------------------------------------------------------------------------------------------------------
补充:
新版的ACE_Condition_Thread_Mutex 实现放在了 ACE_OS::recuersive_mutex_cond_relock ACE_OS::recuersive_mutex_cond_unlock 上,用 ACE_OS::cond_wait((ACE_thread_mutex_t *) &m->lock_available_,(ACE_cond_t*) &m->nesting_mutex_); 同时对2个 互斥体 申请 ,已经解决这个问题了