互斥器类
通常,在多线程任务中,常常为了保证临界区,需要使用一定的手法限制多个进程或者线程的访问,常用的手法通常是互斥,即使用C++中的mutex:
#include <mutex>
using namespace std;
mutex mu;
mu.lock();
...
mu.unlock();
首先来看一个例子,在程序运行过程中,某个需要锁的函数在处理数据时发生了异常:
mutex mu;
try{
mu.lock();
cout<<"lock"<<endl;
throw exception();
cout<<"unlock"<<endl;
mu.unlock();
}
catch(...){}
system("pause");
return 0;
结果:程序可能只上锁,而没有正常解锁,导致死锁的发生。
当然这是不希望发生的情况,我们可以在catch的部分同样进行解锁操作,如下:
catch(...){
cout<<"unlock"<<endl;
mu.unlock(); //解锁操作,防止死锁
}
此时程序的运行是正常的:
但是这就意味着,我们需要在每个异常处理的catch块内都写一个解锁的语句。如果说我们都记得写上该语句固然是好事,但是如果说该语句在某处漏掉了,那么死锁的结局仍可能会发生。为了避免这种情况的发生,需要怎么做呢?
互斥器类就诞生了!
class Locks
{
public:
Locks(mutex* mu):plock(mu,unLock){
Lock(plock.get());
}
private:
shared_ptr<mutex> plock;
};
以智能指针的方式去管理锁,能够实现在作用域外自动实现释放锁的操作,从而避免繁杂的在每处添加解锁操作的语句。因为是智能指针,所以可以保证这个解锁操作是一定能够发生的。
创建对象的时候,就自动进行上锁操作。同时,在对象消失的时候,我们定义了智能指针的删除器,即解锁操作!
完整的代码如下:
#include <iostream>
#include <mutex>
#include <memory>
using namespace std;
void Lock(mutex* mu){
cout<<"lock"<<endl;
mu->lock();
}
void unLock(mutex* mu)
{
cout<<"unlock"<<endl;
mu->unlock();
}
class Locks
{
public:
Locks(mutex* mu):plock(mu,unLock){
Lock(plock.get());
}
private:
shared_ptr<mutex> plock;
};
int main()
{
mutex mu;
try{
Locks m(&mu);
throw exception();
}
catch(exception &e){}
system("pause");
return 0;
}
最终的结果: