建设银行衡阳市分行网站,建e网app下载链接,合肥设计网站,淘宝网页设计多少钱什么是RAII机制
RAII是Resource Acquisition Is Initialization#xff08;翻译成 “资源获取即初始化”#xff09;的简称#xff0c;是C语言的一种管理资源、避免资源泄漏的惯用法#xff0c;该方法依赖构造函数资和析构函数的执行机制。
RAII的做法是使用一个类对象翻译成 “资源获取即初始化”的简称是C语言的一种管理资源、避免资源泄漏的惯用法该方法依赖构造函数资和析构函数的执行机制。
RAII的做法是使用一个类对象在对象的构造函数中获取资源在对象生命期内控制对资源的访问最后在对象消失时其析构函数来释放获取的资源
这里的资源可以是文件句柄内存Event互斥量等等由于系统的资源是有限的就好比自然界的石油铁矿一样不是取之不尽用之不竭的。所以我们在编程安全上要求必须遵循以下几个步骤 申请资源 使用资源 释放资源
在步骤一和步骤二上我们平时都比较容易把握而资源的释放会因为种种编码原因容易被忽略导致系统资源实际没有使用了但却没有释放或者引发其他问题影响了系统资源利用率。 没有使用RAII机制的弊端
那么我们为什么涉及资源管理时建议使用RAII机制进行编码呢
大家可以查看以下两篇文章中的代码我在这两篇文章中都是直接使用系统API进行资源操作没有使用RAII机制进行资源管理在代码阅读和维护上都很不方便。
多线程死锁的产生和解决 利用关键代码段实现线程同步
不推荐的编码方式片段
while (TRUE){//等待直到获得指定对象的所有权EnterCriticalSection(g_csLock); //关键代码段-beginif (g_nIndex nMaxCnt){cout Index g_nIndex ;cout Thread2 is runing endl;//权限释放容易忘记LeaveCriticalSection(g_csLock);}else{//权限释放容易忘记LeaveCriticalSection(g_csLock);//关键代码段-endbreak;} }之所以不推荐这样的编码方式是因为EnterCriticalSection/LeaveCriticalSection必须配对使用很需要依赖人无法根本上解决问题如果LeaveCriticalSection函数没有执行或者忘记添加该API很容易引发问题。 互斥锁应用RAII机制
为了从根本上解决问题减少人为因素引发应用系统问题或者资源泄漏在关键代码段和互斥量这两种锁上示范了如何应用RAII机制简化多线程互斥编码。
关键代码段初始化和锁接口:
class CSLock
{
public:CSLock(){//构造函数时初始化关键代码段对象获取资源InitializeCriticalSection(m_csLock);}~CSLock(){//析构函数时释放为关键代码段对象分配的所有资源释放资源DeleteCriticalSection(m_csLock);}//生命周期内实现对象资源的管理(Lock/Unlock)使用资源void Lock(){EnterCriticalSection(m_csLock);}void Unlock(){LeaveCriticalSection(m_csLock);}//阻止锁的拷贝和赋值
private:CSLock (const CSLock );CSLock operator (const CSLock);
private:CRITICAL_SECTION m_csLock;
}; 创建互斥量对象和锁接口:
class CMutexLock
{
public:CMutexLock(){m_hMutex CreateMutex(NULL, FALSE, NULL);//获取资源}~CMutexLock(){CloseHandle(m_hMutex);//释放资源}void Lock(){WaitForSingleObject(m_hMutex, INFINITE);//使用资源}void Unlock(){ReleaseMutex(m_hMutex);//使用资源}//阻止锁的拷贝和赋值
private:CMutexLock(const CMutexLock);CMutexLock operator (const CMutexLock);
private:HANDLE m_hMutex;
}; 类模板对象,再一次使用RAII机制管理锁对象的占用和释放建议简化锁的应用实现资源的自动回收
templateclass T
class CLockGuard
{
public:CLockGuard(T locker) :m_lockerObj(locker){m_lockerObj.Lock();}~CLockGuard(){m_lockerObj.Unlock();}
private:T m_lockerObj; //必须是引用类型 确保使用的是全局锁否则锁不住
}; 具体示例
#include stdafx.h
#include iostream
#include string
#include Windows.h//创建全局锁保证锁就一个
CSLock g_csLock;
CMutexLock g_Mutex;//全局数据
int g_nIndex 0;
const int nMaxCnt 30;BOOL AddNum(int tid)
{BOOL bRet TRUE;//RAII用法创建lock对象的同时执行lock操作析构后自动调用unlock操作避免人为遗漏CLockGuardCMutexLock lock(g_Mutex);if (g_nIndex nMaxCnt){std::cout Index g_nIndex ;std::cout thread tid is runing std::endl;}else{bRet FALSE;}return bRet;
}//线程函数1
DWORD WINAPI Thread1(LPVOID lpParameter)
{while (true){if (!AddNum(1)){break;}}return 0;
}
//线程函数2
DWORD WINAPI Thread2(LPVOID lpParameter)
{while (true){if (!AddNum(2)){break;}}return 0;
}int _tmain(int argc, _TCHAR* argv[])
{HANDLE harThread[2] {NULL,NULL};//创建新的线程harThread[0] CreateThread(NULL, 0, Thread1, NULL, 0, NULL);//立即执行harThread[1] CreateThread(NULL, 0, Thread2, NULL, 0, NULL);//立即执行WaitForMultipleObjects(2, harThread, TRUE, INFINITE);//良好的编码习惯for (int i 0; i 2; i){CloseHandle(harThread[i]);}return 0;
} 运行效果 从输出结果上看我们的锁是生效的没有出现错乱。这里使用了CLockGuard模板类来进一步简化多线程锁的编码既实现了代码复用也保证了编码安全。其实这编码方式在C11中lock_guard已经应用到了该机制。点击这里查看lock_guard(lock_guard - C Reference)。