一种多线程变量区域锁的实现方法
Posted SpartacusIn21
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一种多线程变量区域锁的实现方法相关的知识,希望对你有一定的参考价值。
多线程变量区域锁类定义
类定义中基于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的区域锁确实生效了,同时只有一个线程访问两个函数共同保护的区域。
以上是关于一种多线程变量区域锁的实现方法的主要内容,如果未能解决你的问题,请参考以下文章