Sunday, February 27, 2011

ReadWriteLock in C++ for Windows using Mutex and Event

As well as Java has its ReentrantReadWriteLock, C# has its own ReaderWriterLock. What about a class that implements the concurrency control for read and write operations in C++ for Windows.

Versão em português desse artigo: ReadWriteLock em C++ no Windows com Mutex e Event.

The ReadWriteLock class permits to allow the parallel access for threads that wants to access an object or a piece of code only for read and ensures exclusive access for the case of write access. Source code bellow:

#include <windows.h>

class ReadWriteLock
{
public:
    ReadWriteLock(void);
    ~ReadWriteLock(void);

private:
    HANDLE hSyncOperationsMutex;
private:
    HANDLE hCanReadEvent;
private:
    HANDLE hCanWriteEvent;
private:
    HANDLE hReadGroup[2];
private:
    HANDLE hWriteGroup[2];
private:
    int readerThreads;

public:
    void writeLock();
public:
    void writeUnlock();
public:
    void readLock();
public:
    void readUnlock();
};

ReadWriteLock::ReadWriteLock(void)
{
    this->hSyncOperationsMutex = CreateMutex(NULL, FALSE, NULL);
    this->hCanReadEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
    this->hCanWriteEvent = CreateEvent(NULL, TRUE, TRUE, NULL);

    this->hReadGroup[0] = hSyncOperationsMutex;
    this->hReadGroup[1] = hCanReadEvent;
    this->hWriteGroup[0] = hSyncOperationsMutex;
    this->hWriteGroup[1] = hCanWriteEvent;

    this->readerThreads=0;
}

ReadWriteLock::~ReadWriteLock(void)
{
    CloseHandle(this->hSyncOperationsMutex);
    CloseHandle(this->hCanReadEvent);
    CloseHandle(this->hCanWriteEvent);
}

void ReadWriteLock::writeLock()
{
    //wait for write flag and mutex
    WaitForMultipleObjects(2, this->hWriteGroup, TRUE, INFINITE);

    ResetEvent(this->hCanReadEvent);
    ResetEvent(this->hCanWriteEvent);

    //dont release the mutex
}

void ReadWriteLock::writeUnlock()
{
    //dont get the already taken mutex

    SetEvent(this->hCanReadEvent);
    SetEvent(this->hCanWriteEvent);

    //release mutex
    ReleaseMutex(this->hSyncOperationsMutex);
}

void ReadWriteLock::readLock()
{
    //wait for read flag and mutex
    WaitForMultipleObjects(2, this->hReadGroup, TRUE, INFINITE);

    //lock write operations on first thread
    if ( this->readerThreads == 0 ) {
        ResetEvent(this->hCanWriteEvent);
    }
    //increase reader count
    this->readerThreads++;

    //release mutex
    ReleaseMutex(this->hSyncOperationsMutex);
}

void ReadWriteLock::readUnlock()
{
    //get mutex
    WaitForSingleObject(this->hSyncOperationsMutex, INFINITE);

    //decrease reader count
    this->readerThreads--;
    //unlock write operations on last reader thread
    if ( this->readerThreads == 0 ) {
        SetEvent(this->hCanWriteEvent);
    }

    //release mutex
    ReleaseMutex(this->hSyncOperationsMutex);
}

Example of class usage:

//create the object
ReadWriteLock* rwLocks = new ReadWriteLock();

void ReadObjects() {
    rwLocks->readLock();

    //in this section all classes has simultaneous access

    rwLocks->readUnlock();
}

void WriteObjects() {
    rwLocks->writeLock();

    //this section is accessed one thread per time
    //and it also forbids accesses to read section

    rwLocks->writeUnlock();
}

No comments:

Post a Comment