设计:
- 包含
'recursive'
互斥体资源的单例。 - 2 个线程使用这个单例来更新/管理数据。
- 无论哪个线程首先尝试访问它,都会创建单例。
- 单例创建具有全局锁以确保我们只调用
mutex attr init
一次mutex init
。
示例代码:两个线程具有相同的流程(只是不同的数据)并且会首先调用 funcX()
instance() 内部有一个全局互斥锁(),以确保只创建 A 的 1 个实例。它还在锁定后不久进行附加(!_instance)检查,以确保我们不会再次创建实例。
class A
{
public:
void funcA();
void funcB();
private:
<members>
<boost::recursive_mutex> m;
};
void funcA()
{
m.lock();
<Do something>
m.unlock();
return;
}
void funcB()
{
m.lock()
<Do something>
m.unlock()
return;
}
void funcX()
{
Singleton::instance().funcA();
return;
}
void funcY()
{
Singleton::instance().funcB();
return;
}
========================================================================
A& Singleton::instance()
{
<Global mutex lock>
if (!_instance)
{
createInstance();
}
<Global mutex unlock>
return _instance;
}
问题:
很少,第一个互斥锁调用不会增加the __count(0)
变量。尽管__owner (thread id)
, __nusers (1)
,__lock (2)
属性都已更新。每当我尝试记录__kind
属性时,问题都不会发生。
初步发现:
当问题发生时,两个线程都在尝试初始化单例(也是互斥体)。由于单例创建中的全局锁,只有 1 个线程继续创建互斥体并将其初始化为recursive
类型。那么锁定互斥量的线程正在查看过期的内存并导致认为互斥量类型是正常的?__kind = 0
. 互斥锁返回成功。并且当调用随后的 unlock 时,互斥锁类型现在被更新recursive
,因为pthread
unlock 没有 0 检查,它最终递减__count
to be INT_MAX
。
else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
== PTHREAD_MUTEX_RECURSIVE_NP, 1))
{
/* Recursive mutex. */
if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
return EPERM;
if (--mutex->__data.__count != 0)
/* We still hold the mutex. */
return 0;
goto normal;
}
Unlock 也返回成功并且互斥锁永远不会被释放,导致另一个线程永远处于等待状态。
发生这种情况的可能原因是什么?可以__kind
以某种方式损坏吗?