多线程变量区域锁类定义
类定义中基于boost库unique_lock和shared_lock定义了读锁ReadLock和写锁WriteLock,将读锁和写锁换成关键区(CRITICAL_SECTION)等也是一样的效果。
变量区域锁主要是基于以下两点:一、变量的作用范围就是锁定的区域范围;二、C++的特性能够保证析构函数能够得到正确执行,这样就能保证锁的释放。
正是基于这两点,这里设计的变量区域互斥锁类,主要的思想是在类对象作用范围内,通过对单个bool型变量的值来判断区域锁是否可用,并对该变量的修改进行加锁保护,该区域互斥锁主要包括三个成员函数:
类构造函数CVariableLock:用于初始化共享互斥体m_lock,以及将变量区域互斥锁外边bool变量指针赋值给m_lock_flag
类析构函数~CVariableLock:在成功获取到锁的情况下,在析构函数中需要将外部标志bool变量恢复为false,表示释放掉区域锁
获取锁状态函数GetLockStatus:在该函数中,主要是获取外部标志bool变量的值,如果为true,表明锁被其他线程占用,循环等待50次,每次延迟10ms,当500ms后外部标志变量还是为true,就获取锁失败;否则获取锁成功,并将外部bool标志变量修改为true,表明区域锁被占用
上面三个函数中,对外部标志bool变量的操作都是在加锁的状态下操作的。
变量区域锁的类CVariableLock代码如下:
//写锁定义
typedef boost::shared_mutex Lock;
typedef boost::unique_lock<Lock> WriteLock;
typedef boost::shared_lock<Lock> ReadLock;
// 区域互斥锁类定义
class CVariableLock
{
public:
CVariableLock(Lock *lock, bool *lock_flag, int thread_id=0);
~CVariableLock(void);
public:
bool GetLockStatus();//获取资源状态,1——可访问,0——不可访问
private:
Lock *m_lock;
bool *m_lock_flag;
bool m_get_lock_flag;
int m_thread_id;
};
// 区域互斥锁构造函数
CVariableLock::CVariableLock(Lock *lock, bool *lock_flag)
{
m_get_lock_flag = false;
if(lock){
m_lock = lock;
}
else{
m_lock = NULL;
}
if(lock_flag){
m_lock_flag = lock_flag;
}
else{
m_lock_flag = NULL;
}
m_thread_id = thread_id;
}
// 区域互斥锁析构函数
CVariableLock::~CVariableLock(void)
{
if(!m_lock || !m_lock_flag){
return;
}
if(m_get_lock_flag){//只有在获取锁成功情况下才重置变量
WriteLock w_lock(*m_lock);
*m_lock_flag = false;
wchar_t str[20];
wsprintf(str,L"线程%d释放区域锁!\n", m_thread_id);
OutputDebugString(str);
}
}
// 区域互斥锁锁状态成员函数
bool CVariableLock::GetLockStatus(){//获取资源状态,返回结果:1——可访问,0——不可访问
if(!m_lock || !m_lock_flag){
return true;
}
bool lock_status = true;
{
{
ReadLock w_lock(*m_lock);
lock_status = *m_lock_flag;
}
int count = 50;
while(lock_status){
if(count <= 0){
break;
}
{
ReadLock w_lock(*m_lock);
lock_status = *m_lock_flag;
}
count--;
Sleep(10);//延时10ms
}
}
bool result = ~(lock_status);
if(result){//获取锁成功
{
WriteLock w_lock(*m_lock);
lock_status = *m_lock_flag;//再次读取变量值
if(lock_status){//已被其他线程锁定
m_get_lock_flag = false;
result = false;
}
else{
m_get_lock_flag = true;
*m_lock_flag = true;
}
}
}
else{//获取锁失败
m_get_lock_flag = false;
}
return result;
}
变量区域锁工作流程图
多线程访问示例
如下,首先定义了外部标志变量lock_flag并初始化为false,表明锁未被占用,同时定义共享互斥体rw_lock。
在Fun1和Fun2中分别定义了局部变量互斥区域锁类对象,这样的话,Fun1函数的作用域和Fun2函数的作用域就是互斥的区域,在多线程访问中,Fun1和Fun2不能同时被两个线程同时访问,这样的话,在Fun1和Fun2中公用的成员变量或者全局变量就能够得到有效的保护,避免多线程同时操作导致的数据不确定或者崩溃。
现在开启10个线程,前5个线程访问Fun1函数,后5个线程访问Fun2函数,可以通过输出看到线程获取区域锁的具体情况:
bool lock_flag = false;
Lock rw_lock;
DWORD WINAPI Fun1(LPVOID lpParameter)
{
int thread_id = *(int*)lpParameter;
CVariableLock lock(&rw_lock,&lock_flag, thread_id);
if(!lock.GetLockStatus()){//获取锁失败
return -1;
}
//获取锁成功,锁定区域1
wchar_t str[20];
wsprintf(str,L"线程%d取得区域锁!\n", thread_id);
OutputDebugString(str);
}
DWORD WINAPI Fun2(LPVOID lpParameter)
{
int thread_id = *(int*)lpParameter;
CVariableLock lock(&rw_lock,&lock_flag, thread_id);
if(!lock.GetLockStatus()){//获取锁失败
return -1;
}
//获取锁成功,锁定区域2
wchar_t str[20];
wsprintf(str,L"线程%d取得区域锁!\n", thread_id);
OutputDebugString(str);
}
int main(){
HANDLE threadHandle[10];
int thread_index[10]={0};
for(int i = 0; i < 5; i++){
thread_index[i]=i;
threadHandle[i] = CreateThread(NULL,0, Fun1, thread_index+i, 0,NULL);
}
for(int j = 5; j < 10; j++){
thread_index[j]=j;
threadHandle[j] = CreateThread(NULL,0, Fun2, thread_index+j, 0,NULL);
}
// 等待线程结束
WaitForMultipleObjects ( 10, threadHandle, TRUE, INFINITE ) ;
OutputDebugString(L"所有线程都已经结束!\n");
for ( int i = 0; i < 10; i++ )
CloseHandle ( threadHandle[i] ) ;
return 0;
}
输出结果为:
可以看到,没有任意两个线程是同时访问Fun1和Fun2函数的,说明Fun1和Fun2的区域锁确实生效了,同时只有一个线程访问两个函数共同保护的区域。