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

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

, 16 Nov 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
Ultra-simple read/write lock pattern implementation in C++.

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 <span class="code-string">"Windows.h"</span>

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 <span class="code-string">"StdAfx.h"</span>

#include <span class="code-string">"ReadWriteLock.h"</span>


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)

Share

About the Author

MSCH@MDD
Web Developer
Denmark Denmark
No Biography provided

Comments and Discussions

 
GeneralBug. Pinmembersssubu10-Jul-09 0:42 
GeneralMy vote of 1 PinmemberC0D1F1ED19-Jan-09 1:05 
Generalwhen multiThread,this class will be deadlock Pinmembernetvc15-Jan-09 16:21 
QuestionCould merge UnlockReader() and UnlockWriter() as Unlock()? PinmemberSheng Yu9-Sep-08 13:07 
GeneralCauses deadlock PinmemberMember 15090248-Aug-08 11:55 
GeneralLook here for a more effective implementation Pinmembersophiavn22-Nov-06 6:22 
GeneralRe: Look here for a more effective implementation PinmemberMSCH@MDD22-Nov-06 21:30 
GeneralRe: Look here for a more effective implementation Pinmembersophiavn23-Nov-06 5:09 
GeneralRe: Look here for a more effective implementation PinmemberMSCH@MDD23-Nov-06 21:28 
QuestionWait objects more efficient? Pinmemberbrettb17-Nov-06 5:08 
AnswerRe: Wait objects more efficient? PinmemberMSCH@MDD20-Nov-06 21:14 
Generalcctor and op= PinmemberSceptic Mole17-Nov-06 0:05 
GeneralRe: cctor and op= PinmemberMSCH@MDD17-Nov-06 0:23 
GeneralRe: cctor and op= PinmemberSp1ff17-Nov-06 4:13 
GeneralHandle leak PinmemberSp1ff16-Nov-06 16:16 
GeneralRe: Handle leak PinmemberMSCH@MDD16-Nov-06 20:34 
QuestionInterlocked Increment? Pinmemberrfmobile16-Nov-06 4:45 
AnswerRe: Interlocked Increment? PinmemberScope16-Nov-06 7:02 
GeneralRe: Interlocked Increment? Pinmemberxaverbirrer17-Nov-06 1:36 
GeneralRe: Interlocked Increment? PinmemberMSCH@MDD20-Nov-06 21:24 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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