Click here to Skip to main content
Click here to Skip to main content

Ultra-simple C++ Read/Write Lock Class for Windows

By , 16 Nov 2006
 

ReadWriteLock Test in action

Introduction

The CReadWriteLock class is a very simple class that implements the Reader/Writer pattern, used for synchronizing multiple thread access to a shared resource. By allowing either multiple reader access or single write access, this class provides a better throughput than standard synchronization mechanisms like Critical Sections.

Background

Looking for a simple solution on the net, I faced the fact that the solutions often were advanced, and not developed in the spirit of KISS (Keep It Simple S*****). Therefore, I decided to implement a simple yet functional solution.

Please note that in order to prevent reader starvation, the CReadWriteLock should only be used when reader access is far more common than writer access. The reason for this is that the implementation does not contain any thread queue or similar to secure the access order, and writer threads will always win this race.

Using the code

Just copy the class (ReadWriteLock.cpp and ReadWriteLock.h) to the project folder, and add the two files to the project.

The code is pretty much self-explanatory; create an instance of CReadWriteLock, and use respectively LockReader()/UnlockReader() and LockWriter()/UnlockWriter() before using the shared resource.

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);
}

History

  • 2006-11-01: Version 1.0 - First release.
  • 2006-11-20: Version 1.1 - Shallow copy is prevented by implementing private constructor and assignment operator.
  • 2006-11-21: Version 1.2 - while loop waiting for no readers in LockWriter() is replaced with WaitForSingleObject().

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

MSCH@MDD
Web Developer
Denmark Denmark
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralBug.membersssubu9 Jul '09 - 23:42 
GeneralMy vote of 1memberC0D1F1ED19 Jan '09 - 0:05 
Generalwhen multiThread,this class will be deadlockmembernetvc15 Jan '09 - 15:21 
QuestionCould merge UnlockReader() and UnlockWriter() as Unlock()?memberSheng Yu9 Sep '08 - 12:07 
GeneralCauses deadlockmemberMember 15090248 Aug '08 - 10:55 
GeneralLook here for a more effective implementationmembersophiavn22 Nov '06 - 5:22 
GeneralRe: Look here for a more effective implementationmemberMSCH@MDD22 Nov '06 - 20:30 
GeneralRe: Look here for a more effective implementationmembersophiavn23 Nov '06 - 4:09 
GeneralRe: Look here for a more effective implementationmemberMSCH@MDD23 Nov '06 - 20:28 
QuestionWait objects more efficient?memberbrettb17 Nov '06 - 4:08 
AnswerRe: Wait objects more efficient?memberMSCH@MDD20 Nov '06 - 20:14 
Generalcctor and op=memberSceptic Mole16 Nov '06 - 23:05 
GeneralRe: cctor and op=memberMSCH@MDD16 Nov '06 - 23:23 
GeneralRe: cctor and op=memberSp1ff17 Nov '06 - 3:13 
GeneralHandle leakmemberSp1ff16 Nov '06 - 15:16 
GeneralRe: Handle leakmemberMSCH@MDD16 Nov '06 - 19:34 
QuestionInterlocked Increment?memberrfmobile16 Nov '06 - 3:45 
AnswerRe: Interlocked Increment?memberScope16 Nov '06 - 6:02 
GeneralRe: Interlocked Increment?memberxaverbirrer17 Nov '06 - 0:36 
GeneralRe: Interlocked Increment?memberMSCH@MDD20 Nov '06 - 20:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 16 Nov 2006
Article Copyright 2006 by MSCH@MDD
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid