自动锁重复释放的问题

文章讨论了自动锁在C++中的实现,以及如何防止在对象析构时导致的资源二次释放问题。错误的代码示例展示了在释放对象时可能导致的问题,即锁和对象同时被销毁。解决方案包括先释放锁然后再删除对象,或者使用原子操作来确保减操作的线程安全性。C++11的库也被提及作为支持原子操作的工具。
摘要由CSDN通过智能技术生成

自动锁重复释放

自动锁的实现,就是在对象析构的时候,销毁线程锁。

这种套路在面试中经常遇到:怎么优雅地统计一个函数的执行时间

///自动锁类
/**定义一个局部包装类对象,定义是加读锁,超出范围时局部对象释放,读锁也自动释放;
 * 当一个函数内加锁后,确保此函数任何退出点锁都会释放,以避免死锁 
 * 注意:要防止有些编译器把未被引用的局部对象优化掉.
 */
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>

头文件说明
CAtomicatomic.h支持short int long类型、++ --操作、Set Get支持、比较运算符
CAtomic<long> id = 0; //赋值构造
int value = id++; //获取自增后计数器值 线程安全
id.Set(0); //设置计数器值
id.Get(); //获取计数器当前值
if(id == 0) //与数值类型进行比较
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值