扩展阅读
  • java命名空间java.awt.event类windowevent的类成员方法: window_closed定义及介绍
  • 我配置好smb服务器windows能访问我,我不能访问windows
  • java命名空间javax.accessibility类accessiblerelation的类成员方法: parent_window_of_property定义及介绍
  • 大家推荐一个windows下的java开发平台。工具本身是为windows优化的。jbuilder太慢。
  • java命名空间java.awt.event类windowevent的类成员方法: window_opened定义及介绍
  • windows下写的代码 gb2312 如何转成 LINUX和WINDOWS都可正常显示的代码
  • java命名空间java.awt.event类windowevent的类成员方法: window_state_changed定义及介绍
  • 用linux(服)windows(客)传输文件,windows端可以,linux端不可以,怎么回事???
  • java命名空间java.awt.event类windowevent的类成员方法: window_first定义及介绍
  • windows下用wincvs弄下来的emacs源码全是windows格式的,晕!!!
  • java命名空间java.awt.event类windowevent的类成员方法: window_deiconified定义及介绍
  • linux环境下安装windows打印机问题。。没有驱动,能否在无界面的linux上安装windows虚拟机??
  • java命名空间java.awt类window的类成员方法: getownerlesswindows定义及介绍
  • 为什么我装了linux后,再用智能安装windows的方法安装winodw xp 或window.net....
  • java命名空间javax.swing.plaf.synth类region的类成员方法: tool_bar_drag_window定义及介绍
  • 请指点: 在windows下能否通过程序来获取linux下的用户列表,甚至通过自己写的windows程序界面增加修改linux的用户
  • java命名空间javax.accessibility类accessiblerelation的类成员方法: parent_window_of定义及介绍
  • 如何修改启动菜单的启动顺序(linux,windows),我想让系统默认启动到windows.谢谢!!
  • java命名空间java.awt类window的类成员方法: dispose定义及介绍
  • 急需windows server 2003系统c:windowssystem32文件夹下winlogon.exe、licdll.dll两个文件,在线等待!
  • java命名空间java.awt类window的类成员方法: getwindows定义及介绍
  • 想知道为什么window程序能在不同的硬件的windows平台上运行,而linux不行
  •  
    当前位置:  编程语言>c/c++

    windows下c/c++读写锁实现原理及代码参考

     
        发布时间:2013-10-17  


        本文导语:  读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允...

      读写实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。

    现在win32api,用c++实现自己的读写锁。这组api包括:createmutex,createevent,waitforsingleobjectwaitformultipleobjectsresetevent,releasemutex,setevent,closehandle.

      WindowsVista 和 Server2008以后才开始提供读写锁API,即SRW系列函数(InitializeSRWLock, AcquireSRWLockShared,

    AcquireSRWLockExclusive等).那么如何实现一个自己的读写锁呢?

    读写锁的目的和要求

     读写锁的最基本目的是读锁可以共享,写锁必须独占.另外,还有两点需要特别考虑:

    1) 如果有写锁请求在等待,则新的读锁请求也应该等待.否则程序可能永远也没有机会获得写锁.

    2) 一旦写锁被释放,所有在等待中的读锁和写锁请求应该可以公平竞争,而不管请求的先后,只要之前已经在等待就应该有获得锁的机会.

    如果说第一点还可以再斟酌一下的话,第二点应该是必须要保证的.

    读写锁的实现

    总体思路比较简单:读写锁内部维护一些状态值,用临界端CRITICAL_SECTION保护这些状态值访问原子性事件对象配合实现等待.

    进入锁的情况:

    1) 如果当前锁状态为空闲,则不管写锁还是读锁请求都允许进入,并设置相应的状态值.

    2) 如果当前锁状态是读,新的写锁请求需要等待事件通知,并把写锁等待计数加一.

    3) 如果当前锁状态是读,新的读锁请求:

    (1) 如果没有写锁请求在等待,则允许读锁进入,并把读锁计数加一.

    (2) 如果有写锁请求正在等待,则等待事件通知,并读锁等待计数加一(这样做的目的如上文所述,要使写锁有机会进入).

    4) 如果当前锁状态为写,则不管读锁请求还是写锁请求,都等待事件通知并分别给读锁等待计数或者写锁等待计数加一.

    解锁的情况:

    如果锁释放时,读锁等待计数或者写锁等待计数不为0,则触发事件对象.

      我使用手动事件对象,这样的话一旦锁被释放,所有正在等待的锁请求都将被激活,然后重新以竞争临界段的方式竞争锁进入权以保证公平性.不管等待请求时的先后,只要是锁释放进入等待状态则锁一旦释放获得进入权的机会是均等的.

     读写锁实现参考代码1:

    #define RWLOCK_IDLE 0 /* 空闲 */
    #define RWLOCK_R 0x01 /* 读锁 */
    #define RWLOCK_W 0x02 /* 写锁 */
    class RWLock
    {
    private:
    int _st; /* 锁状态值 */
    int _rlockCount; /* 读锁计数 */
    int _rwaitingCount; /* 读等待计数 */
    int _wwaitingCount; /* 写等待计数 */
    HANDLE _ev; /* 通知事件 Event */
    //HANDLE _stLock; /* 访问状态值互斥量 */ /* 如果需要等待超时,则用 Mutex */
    CRITICAL_SECTION _stLock;
    public:
    RWLock(void);
    ~RWLock(void);
    void rlock();
    void wlock();
    void unlock();
    };
    RWLock::RWLock(void)
    : _rlockCount(0),
    _st(RWLOCK_IDLE),
    _rwaitingCount(0),
    _wwaitingCount(0)
    {
    //_stLock = CreateMutex(NULL, FALSE, NULL);
    //assert(_stLock != INVALID_HANDLE_VALUE);
    InitializeCriticalSection(&_stLock);
    /*
    * 假设当前有多个读锁请求正在等待写锁释放,那么当写锁被释放时,所有这些读锁都应该有机会获得执行.
    */
    _ev = CreateEvent(NULL, TRUE, FALSE, NULL);
    assert(_ev != INVALID_HANDLE_VALUE);
    }
    RWLock::~RWLock(void)
    {
    //CloseHandle(_stLock);
    DeleteCriticalSection(&_stLock);
    CloseHandle(_ev);
    }
    void RWLock::rlock()
    {
    bool isWaitReturn = false;
    while(1)
    {
    //WaitForSingleObject(_stLock, INFINITE);
    EnterCriticalSection(&_stLock);
    if(isWaitReturn)
    {
    /*
    * 等待事件返回,重新竞争锁.
    */
    --_rwaitingCount;
    }
    if(_st == RWLOCK_IDLE)
    {
    /*
    * 空闲状态,直接得到控制权
    */
    _st = RWLOCK_R;
    _rlockCount++;
    //ReleaseMutex(_stLock);
    LeaveCriticalSection(&_stLock);
    break;
    }
    else if( _st == RWLOCK_R)
    {
    if(_wwaitingCount > 0)
    {
    /*
    * 有写锁正在等待,则一起等待,以使写锁能获得竞争机会.
    */
    ++_rwaitingCount;
    ResetEvent(_ev);
    //SignalObjectAndWait(_stLock, _ev, INFINITE, FALSE);
    LeaveCriticalSection(&_stLock);
    /*
    * 虽然 LeaveCriticalSection() 和 WaitForSingleObject() 之间有一个时间窗口,
    * 但是由于windows平台的事件信号是不会丢失的,所以没有问题.
    */
    WaitForSingleObject(_ev, INFINITE);
    /*
    * 等待返回,继续尝试加锁.
    */
    isWaitReturn = true;
    }
    else
    {
    /*
    * 得到读锁,计数+1
    */
    ++_rlockCount;
    //ReleaseMutex(_stLock);
    LeaveCriticalSection(&_stLock);
    break;
    }
    }
    else if(_st == RWLOCK_W)
    {
    /*
    * 等待写锁释放
    */
    ++_rwaitingCount;
    ResetEvent(_ev);
    //SignalObjectAndWait(_stLock, _ev, INFINITE, FALSE);
    LeaveCriticalSection(&_stLock);
    WaitForSingleObject(_ev, INFINITE);
    /*
    * 等待返回,继续尝试加锁.
    */
    isWaitReturn = true;
    }
    else
    {
    assert(0);
    break;
    }
    }
    }
    void RWLock::wlock()
    {
    bool isWaitReturn = false;
    while(1)
    {
    //WaitForSingleObject(_stLock, INFINITE);
    EnterCriticalSection(&_stLock);
    if(isWaitReturn) --_wwaitingCount;
    if(_st == RWLOCK_IDLE)
    {
    _st = RWLOCK_W;
    //ReleaseMutex(_stLock);
    LeaveCriticalSection(&_stLock);
    break;
    }
    else
    {
    ++_wwaitingCount;
    ResetEvent(_ev);
    //SignalObjectAndWait(_stLock, _ev, INFINITE, FALSE);
    LeaveCriticalSection(&_stLock);
    WaitForSingleObject(_ev, INFINITE);
    isWaitReturn = true;
    }
    }
    }
    void RWLock::unlock()
    {
    //WaitForSingleObject(_stLock, INFINITE);
    EnterCriticalSection(&_stLock);
    if(_rlockCount > 0)
    {
    /* 读锁解锁 */
    --_rlockCount;
    if( 0 == _rlockCount)
    {
    _st = RWLOCK_IDLE;
    /* 释放 */
    if( _wwaitingCount > 0 || _rwaitingCount > 0 )
    {
    /*
    * 此时有锁请求正在等待,激活所有等待的线程.(手动事件).
    * 使这些请求重新竞争锁.
    */
    SetEvent(_ev);
    }
    else
    {
    /* 空闲 */
    }
    }
    else
    {
    /* 还有读锁 */
    }
    }
    else
    {
    _st = RWLOCK_IDLE;
    /* 写锁解锁 */
    if( _wwaitingCount > 0 || _rwaitingCount > 0 )
    {
    /*
    * 如果在占有互斥量_stLock的情况下,触发事件,那么可能会使一些锁请求不能得到竞争机会.
    * 假设调用unlock时,另一个线程正好调用rlock或者wlock.如果不释放互斥量,只有之前已经等待的锁请求有机会获得锁控制权.
    */
    SetEvent(_ev);
    }
    else
    {
    /* 空闲 */
    }
    }
    //ReleaseMutex(_stLock);
    LeaveCriticalSection(&_stLock);
    }


    读写锁参考代码2:

    class ReadWriteLock
    {
    public:
    int m_currentLevel;
    int m_readCount;
    HANDLE m_unlockEvent;
    HANDLE m_accessMutex;
    CRITICAL_SECTION m_csStateChange;
    public:
    ReadWriteLock
    {
       m_currentLevel = LOCK_LEVEL_NONE;
       m_readCount = 0;
       m_unlockEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL );
       m_accessMutex = ::CreateMutex( NULL, FALSE, NULL );
       ::InitializeCriticalSection( &m_csStateChange );
    }
    ~ReadWriteLock
    {
       ::DeleteCriticalSection( &m_csStateChange );
       if(m_accessMutex) ::CloseHandle( m_accessMutex );
       if(m_unlockEvent) ::CloseHandle( m_unlockEvent );
    }
    bool lock(level, timeout = INFINITE)
    {
       bool bresult = true;
       DWORD waitResult = 0;
       waitResult = ::WaitForSingleObject( m_accessMutex, timeout );
       if(waitResult != WAIT_OBJECT_0) return false;
       if(level==LOCK_LEVEL_READ && m_currentLevel != LOCK_LEVEL_WRITE )
       {
        ::EnterCriticalSection( &m_csStateChange );
        m_currentLevel = level;
        m_readCount +=1;
        ::ReEvent( m_unlockEvent );
        ::LeaveCriticalSection( &m_csStateChange );
       }
       else if(level== LOCK_LEVEL_READ && m_currentLevel == LOCK_LEVEL_WRITE )
       {
        waitResult = ::WaitForSingleObject( m_unlockEvent, timeout );
        if(waitResult== WAIT_OBJECT_0)
        {
         ::EnterCriticalSection( &m_csStateChange );
         m_currentLevel = level;
         m_readCount +=1;
         ::ReEvent( m_unlockEvent );
         ::LeaveCriticalSection( &m_csStateChange );
        }
        else bresult = false;
       }
       else if(level== LOCK_LEVEL_WRITE && m_currentLevel == LOCK_LEVEL_NONE )
       {
        ::EnterCriticalSection( &m_csStateChange );
        m_currentLevel = level;
        ::ReEvent( m_unlockEvent );
        ::LeaveCriticalSection( &m_csStateChange );
       }
       else if(level== LOCK_LEVEL_WRITE && m_currentLevel != LOCK_LEVEL_NONE )
       {
        waitResult = ::WaitForSingleObject( m_unlockEvent, timeout );[Page]
         if(waitResult==WAIT_OBJECT_0 )
         {
          ::EnterCriticalSection( &m_csStateChange );
          m_currentLevel = level;
          ::ReEvent( m_unlockEvent );
          ::LeaveCriticalSection( &m_csStateChange );
         }
         else bresult = false;
       }
       ::ReleaseMutex( m_accessMutex );
       return bresult;
    } // lock
    bool unlock
    {
       ::EnterCriticalSection( &m_csStateChange );
       if(m_currentLevel== LOCK_LEVEL_READ )
       {
        m_readCount --;
        if(m_readCount== 0)
        {
         m_currentLevel = LOCK_LEVEL_NONE;
         ::SetEvent (m_unlockEvent);
        }
       }
       else if(m_currentLevel== LOCK_LEVEL_WRITE )
       {
        m_currentLevel = LOCK_LEVEL_NONE;
        ::SetEvent ( m_unlockEvent );
       }
       ::LeaveCriticalSection( &m_csStateChange );
       return true;
    }
    };


    • 本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
      本站(WWW.)站内文章除注明原创外,均为转载,整理或搜集自网络.欢迎任何形式的转载,转载请注明出处.
      转载请注明:文章转载自:[169IT-IT技术资讯]
      本文标题:windows下c/c++读写锁实现原理及代码参考
    相关文章推荐:
  • java命名空间java.awt类window.accessibleawtwindow的类成员方法: window.accessibleawtwindow定义及介绍
  • 怎么在Linux下改windows系统文件啊,我把windows的BOOT.INI改了,windows启动不了
  • java命名空间java.awt类window的类成员方法: window定义及介绍
  • x-windows如何安装在linux(rdehat9)上面呢,是不是x-windows也分windows和linux版本的吗?
  • java命名空间java.awt.event类windowevent的类成员方法: window_activated定义及介绍
  • linux和windows串口问题!?linux向windows端发送,第一次write正常,继续write,windows接收到的就变成乱码了,这是什么原因??????
  • java命名空间java.awt.event类windowevent的类成员方法: window_deactivated定义及介绍
  • redhat7.3+window me +windows xp 共存,MBR在windows me 分区,现在要重裝windwos me,怎么办?
  • java命名空间java.awt.event类windowevent的类成员方法: window_gained_focus定义及介绍
  • 装了Linux和Windows,怎样默认进入Windows
  • java命名空间java.awt.event类windowevent的类成员方法: window_lost_focus定义及介绍
  • Linux与windows共存时,如何将Windows设置为默认启动系统?
  • java命名空间java.awt类window的类成员方法: setvisible定义及介绍
  • linux 、 unix给windows传送文件windows
  • java命名空间java.awt类systemcolor的类成员方法: window定义及介绍
  • 怎样是编好的java application在windows上像windows应用程序一样直接运行
  • java命名空间javax.accessibility类accessiblerole的类成员方法: window定义及介绍
  • windows 和linux双系统,重装windows后,无法启动linux?
  • java命名空间java.awt.event类keyevent的类成员方法: vk_windows定义及介绍
  • 如何将linux的一台机器加入windows 2000的域?并且通过一windows的机器上网?
  • WinDows8最新版文件夹加密
  • 为什么在安装了WINDOWS和LINUX的电脑上,重装WINDOWS会破坏MBR?


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3