一种多线程变量区域锁的实现方法

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的区域锁确实生效了,同时只有一个线程访问两个函数共同保护的区域。

 

以上是关于一种多线程变量区域锁的实现方法的主要内容,如果未能解决你的问题,请参考以下文章

并发编程:ThreadLocal

分布式锁的作用及实现

乐观锁的一种实现方式——CAS

Redis 分布式锁的作用及实现(序列四)

两种多线程创建方式区别

使用条件变量优于互斥锁的优点