自动锁重复释放
自动锁的实现,就是在对象析构的时候,销毁线程锁。
这种套路在面试中经常遇到:怎么优雅地统计一个函数的执行时间
///自动锁类
/**定义一个局部包装类对象,定义是加读锁,超出范围时局部对象释放,读锁也自动释放;
* 当一个函数内加锁后,确保此函数任何退出点锁都会释放,以避免死锁
* 注意:要防止有些编译器把未被引用的局部对象优化掉.
*/
class API_EXPORT CAutoMutex
{
public:
CAutoMutex(CThreadMutex * pMutex)
{
m_pMutex=pMutex;
pMutex->Acquire();
};
~CAutoMutex()
{
m_pMutex->Release();
};
private:
CThreadMutex * m_pMutex;
};
原有写法:
先看下错误的写法:
void CAlgoEntrust::Release(){
FBASE2::CAutoMutex lck(&m_hRef);
--m_iRef;
if(0==m_iRef){
delete this;
}
}
m_hRef这把锁作为CAlgoEntrust类的一个成员变量,在delete this后,就随着CAlgoEntrust实例的释放,它也被释放了,
但当Release执行结束时,CAutoMutex类会调用析构函数释放m_pMutex,而m_pMutex与m_hRef指向同一块地址,这个已被释放的地址被再次释放,导致core的产生
解决方法一:
先释放锁变量,再释放实例
void CAlgoEntrust::Release(){
int ret=1;
{
FBASE2::CAutoMutex lck(&m_hRef);
--m_iRef;
ret=m_iRef;
}
if(0==ret){
delete this;
}
}
解决方法二:
原子锁:由于自动锁的目的只是为了保证–m_iRef的原子操作,那么直接用原子操作就行
int inc(int *value, int add) {
int old;
__asm__ volatile (
// xaddl 第2个参数加第1个参数并把值存储到第一个参数;lock,锁cpu操作内存的总线
// 锁总线、锁缓存的平时也用不到,这里不赘述了
"lock; xaddl %2, %1;"
: "=a" (old) // old:第0个参数
: "m" (*value), "a" (add) // value第一个参数,add是第二个参数
: "cc", "memory"
);
return old;
}
void CAlgoEntrust::Release(){
inc(m_iRef, -1); // 原子操作
if(0==m_iRef){
delete this;
}
}
C++11已支持原子锁,<atomic.h>
类 | 头文件 | 说明 |
---|---|---|
CAtomic | atomic.h | 支持short int long类型、++ --操作、Set Get支持、比较运算符 |
CAtomic<long> id = 0; //赋值构造
int value = id++; //获取自增后计数器值 线程安全
id.Set(0); //设置计数器值
id.Get(); //获取计数器当前值
if(id == 0) //与数值类型进行比较