Click here to Skip to main content
15,883,745 members
Articles / Programming Languages / C++/CLI
Article

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

Rate me:
Please Sign up or sign in to vote.
3.43/5 (11 votes)
16 Nov 2006CPOL1 min read 117.3K   1.4K   21   20
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

C++
##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

C++
#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)


Written By
Web Developer
Denmark Denmark
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralBug. Pin
sssubu9-Jul-09 23:42
sssubu9-Jul-09 23:42 
GeneralMy vote of 1 Pin
C0D1F1ED19-Jan-09 0:05
C0D1F1ED19-Jan-09 0:05 
Generalwhen multiThread,this class will be deadlock Pin
seanleee15-Jan-09 15:21
seanleee15-Jan-09 15:21 
QuestionCould merge UnlockReader() and UnlockWriter() as Unlock()? Pin
Sheng Yu9-Sep-08 12:07
Sheng Yu9-Sep-08 12:07 
GeneralCauses deadlock Pin
Member 15090248-Aug-08 10:55
Member 15090248-Aug-08 10:55 
GeneralLook here for a more effective implementation Pin
sophiavn22-Nov-06 5:22
sophiavn22-Nov-06 5:22 
GeneralRe: Look here for a more effective implementation Pin
MSCH@MDD22-Nov-06 20:30
MSCH@MDD22-Nov-06 20:30 
GeneralRe: Look here for a more effective implementation Pin
sophiavn23-Nov-06 4:09
sophiavn23-Nov-06 4:09 
GeneralRe: Look here for a more effective implementation Pin
MSCH@MDD23-Nov-06 20:28
MSCH@MDD23-Nov-06 20:28 
QuestionWait objects more efficient? Pin
brettb17-Nov-06 4:08
brettb17-Nov-06 4:08 
AnswerRe: Wait objects more efficient? Pin
MSCH@MDD20-Nov-06 20:14
MSCH@MDD20-Nov-06 20:14 
Generalcctor and op= Pin
Sceptic Mole16-Nov-06 23:05
Sceptic Mole16-Nov-06 23:05 
GeneralRe: cctor and op= Pin
MSCH@MDD16-Nov-06 23:23
MSCH@MDD16-Nov-06 23:23 
GeneralRe: cctor and op= Pin
Sp1ff17-Nov-06 3:13
Sp1ff17-Nov-06 3:13 
GeneralHandle leak Pin
Sp1ff16-Nov-06 15:16
Sp1ff16-Nov-06 15:16 
GeneralRe: Handle leak Pin
MSCH@MDD16-Nov-06 19:34
MSCH@MDD16-Nov-06 19:34 
QuestionInterlocked Increment? Pin
unitrunker16-Nov-06 3:45
unitrunker16-Nov-06 3:45 
AnswerRe: Interlocked Increment? Pin
Scope16-Nov-06 6:02
Scope16-Nov-06 6:02 
GeneralRe: Interlocked Increment? Pin
x-b17-Nov-06 0:36
x-b17-Nov-06 0:36 
GeneralRe: Interlocked Increment? Pin
MSCH@MDD20-Nov-06 20:24
MSCH@MDD20-Nov-06 20:24 

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

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