什么是RAII?
????????RAII是Resource Acquisition Is Initialization(wiki上面翻译成 “资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。RAII的做法是使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。
为什么要使用RAII?
????????上面说到RAII是用来管理资源、避免资源泄漏的方法。那么,用了这么久了,也写了这么多程序了,口头上经常会说资源,那么资源是如何定义的? 在计算机系统中,资源是数量有限且对系统正常运行具有一定作用的元素。比如:网络套接字、互斥锁、文件句柄和内存等等,它们属于系统资源。由于系统的资源是有限的,就好比自然界的石油,铁矿一样,不是取之不尽,用之不竭的。 所以,我们在编程使用系统资源时,都必须遵循一个步骤:
第一步和第二步缺一不可,因为资源必须要申请才能使用的,使用完成以后,必须要释放,如果不释放的话,就会造成资源泄漏。
我们来举个示例: ?
#include <iostream>
using namespace std;
int main()
{
int* arr = new int[10];
//业务代码.....
delete[] arr;
arr = nullptr;
return 0;
}
????????但是如果程序很复杂的时候,需要为所有的new 分配的内存delete掉,导致效率下降,更可怕的是,程序的可理解性和可维护性明显降低了,当操作增多时,处理资源释放的代码就会越来越多,越来越乱。如果某一个操作发生了异常而导致释放资源的语句没有被调用,怎么办?这个时候,RAII机制就可以派上用场了。
如何使用RAII?
????????当我们在一个函数内部使用局部变量,当退出了这个局部变量的作用域时,这个变量也就别销毁了;当这个变量是类对象时,这个时候,就会自动调用这个类的析构函数,而这一切都是自动发生的,不要程序员显示的去调用完成。这个也太好了,RAII就是这样去完成的。
由于系统的资源不具有自动释放的功能,而C++中的类具有自动调用析构函数的功能。如果把资源用类进行封装起来,对资源操作都封装在类的内部,在析构函数中进行释放资源。当定义的局部变量的生命结束时,它的析构函数就会自动的被调用,如此,就不用程序员显示的去调用释放资源的操作了。
使用RAII 机制的代码: ?
#include <iostream>
#include <atomic>//C++11线程库提供的原子类
#include <thread>//C++线程类库的头文件
#include <mutex>
#include <vector>
int count = 0;
std::mutex mutex;
//线程函数
void sumTask()
{
//每个线程给count加10次
for (int i = 0; i < 10; ++i)
{
{
std::lock_guard<std::mutex> lock(mutex);
count++;
}
;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
int main()
{
//创建10个线程放在容器当中
std::vector<std::thread> vec;
for (int i = 0; i < 10; ++i)
{
vec.push_back(std::thread(sumTask));
}
//等待线程执行完成
for (unsigned int i = 0; i < vec.size(); ++i)
{
vec[i].join();
}
//所有子线程运行结束,count的结果每次运行应该都是10000
std::cout << "count : " << count << std::endl;
return 0;
}
?红框框起来就是利用了RAII思想,定义了一个lock_gurad 进行上锁,当离开{ } 作用域时,自动释放锁。来看一下lock_guard的实现:
// CLASS TEMPLATE lock_guard
template<class _Mutex>
class lock_guard
{ // class with destructor that unlocks a mutex
public:
using mutex_type = _Mutex;
explicit lock_guard(_Mutex& _Mtx)
: _MyMutex(_Mtx)
{ // construct and lock
_MyMutex.lock();
}
lock_guard(_Mutex& _Mtx, adopt_lock_t)
: _MyMutex(_Mtx)
{ // construct but don't lock
}
~lock_guard() noexcept
{ // unlock
_MyMutex.unlock();
}
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
private:
_Mutex& _MyMutex;
};
?
|