65.9K
CodeProject 正在变化。 阅读更多。
Home

适用于 Windows 的超简单 C++ 读/写锁类

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.43/5 (10投票s)

2006年11月16日

CPOL

1分钟阅读

viewsIcon

119560

downloadIcon

1456

在 C++ 中实现超简单的读/写锁模式。

ReadWriteLock Test in action

引言

CReadWriteLock 类是一个非常简单的类,它实现了读者/写者模式,用于同步对共享资源的多个线程访问。 通过允许多个读者访问或单个写者访问,该类比标准同步机制(如临界区)提供更高的吞吐量。

背景

在网上寻找简单的解决方案时,我发现许多解决方案过于复杂,并且没有遵循 KISS(保持简单,傻瓜)原则。 因此,我决定实现一个简单但实用的解决方案。

请注意,为了防止读者饥饿,CReadWriteLock 仅应在读者访问远比写者访问更常见时使用。 这是因为该实现不包含任何线程队列或类似机制来保证访问顺序,并且写者线程将始终赢得这场竞争。

使用代码

只需将类(ReadWriteLock.cppReadWriteLock.h)复制到项目文件夹中,并将这两个文件添加到项目中即可。

代码几乎不言自明;创建一个 CReadWriteLock 实例,并在使用共享资源之前分别使用 LockReader()/UnlockReader()LockWriter()/UnlockWriter()

ReadWriteLock.h

##pragma once
#include "Windows.h"

class CReadWriteLock
{
public:
    //! Constructor.

    CReadWriteLock(void);
    //! Destructor.

    virtual ~CReadWriteLock(void);
    
    //! Lock for reader access.

    void LockReader();
    //! Unlock reader access.

    void UnlockReader();
    
    //! Lock for writer access.

    void LockWriter();
    //! Unlock writer access.

    void UnlockWriter();

private:
    //! Private copy constructor.

    CReadWriteLock(const CReadWriteLock &cReadWriteLock);
    //! Private assignment operator.

    const CReadWriteLock& operator=(const CReadWriteLock &cReadWriteLock);

    //! Increment number of readers.

    void IncrementReaderCount();
    //! Decrement number of readers.

    void DecrementReaderCount();

    //! Writer access event.

    HANDLE m_hWriterEvent;
    //! No readers event.

    HANDLE m_hNoReadersEvent;
    //! Number of readers.

    int m_nReaderCount;
    
    //! Critical section for protecting lock writer method.

    CRITICAL_SECTION m_csLockWriter;
    //! Critical section for protecting reader count.

    CRITICAL_SECTION m_csReaderCount;
};

ReadWriteLock.cpp

#include "StdAfx.h"

#include "ReadWriteLock.h"


CReadWriteLock::CReadWriteLock(void)
 : m_nReaderCount(0), m_hWriterEvent(NULL), m_hNoReadersEvent(NULL)
{
    // Create writer event with manual reset and default signaled state.
    // 

    // State:

    //          Signaled     = Writer has currently not access.
    //          Non-signaled = Writer has currently access, block readers.
    //

    m_hWriterEvent    = CreateEvent(NULL, TRUE, TRUE, NULL);
    
    // Create no readers event with manual reset and default signaled state.
    // 

    // State:

    //          Signaled     = No readers have currently access.
    //          Non-signaled = Some readers have currently access, block writer.
    //

    m_hNoReadersEvent = CreateEvent(NULL, TRUE, TRUE, NULL);

    //
    // Initialize critical sections.

    InitializeCriticalSection(&m_csLockWriter);
    InitializeCriticalSection(&m_csReaderCount);
}

CReadWriteLock::CReadWriteLock(const CReadWriteLock &cReadWriteLock)
{
}

const CReadWriteLock& CReadWriteLock::operator=(const CReadWriteLock &cReadWriteLock)
{
    return *this;
}


CReadWriteLock::~CReadWriteLock(void)
{
    //
    // Delete critical sections.

    DeleteCriticalSection(&m_csLockWriter);
    DeleteCriticalSection(&m_csReaderCount);

    // Close the writer event.

    CloseHandle(m_hWriterEvent);
    // Close the no readers event.

    CloseHandle(m_hNoReadersEvent);
}


void CReadWriteLock::LockReader()
{
    bool bLoop = true;

    // Loop.

    while(bLoop)
    {
        // Wait for Writer event to be signaled.

        WaitForSingleObject(m_hWriterEvent, INFINITE);
        // Increment number of readers.

        IncrementReaderCount();
        // If writer is become non-signaled fall back (double locking).

        if(WaitForSingleObject(m_hWriterEvent, 0) != WAIT_OBJECT_0)
        {
            // Decrement number of readers.
            DecrementReaderCount();
        }
        else
        {
            // Breakout.

            bLoop = false;
        }
    }
}


void CReadWriteLock::UnlockReader()
{
    // Decrement number of readers.

    DecrementReaderCount();
}


void CReadWriteLock::LockWriter()
{
    // Enter critical section (prevent more than one writer).

    EnterCriticalSection(&m_csLockWriter);
    // Wait for current writer.

    WaitForSingleObject(m_hWriterEvent, INFINITE);
    // Set writer to non-signaled.

    ResetEvent(m_hWriterEvent);
    // Wait for current readers to finish.

    WaitForSingleObject(m_hNoReadersEvent, INFINITE); 
    // Leave critical section.

    LeaveCriticalSection(&m_csLockWriter);
}


void CReadWriteLock::UnlockWriter()
{
    // Set writer event to signaled.

    SetEvent(m_hWriterEvent);
}


void CReadWriteLock::IncrementReaderCount()
{
    // Enter critical section.

    EnterCriticalSection(&m_csReaderCount);
    // Increase reader count.

    m_nReaderCount++;
    // Reset the no readers event.

    ResetEvent(m_hNoReadersEvent);
    // Leave critical section.

    LeaveCriticalSection(&m_csReaderCount);
}


void CReadWriteLock::DecrementReaderCount()
{
    // Enter critical section.

    EnterCriticalSection(&m_csReaderCount);
    // Decrease reader count.

    m_nReaderCount--;
    // Are all readers out?

    if(m_nReaderCount <= 0)
    {
        // Set the no readers event.

        SetEvent(m_hNoReadersEvent);
    }
    // Leave critical section.

    LeaveCriticalSection(&m_csReaderCount);
}

历史

  • 2006-11-01:版本 1.0 - 首次发布。
  • 2006-11-20:版本 1.1 - 通过实现私有构造函数和赋值运算符来防止浅拷贝。
  • 2006-11-21:版本 1.2 - LockWriter() 中等待无读者的 while 循环被 WaitForSingleObject() 替换。
© . All rights reserved.