/* * Copyright (C) 2007-2023 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #ifndef BU_READ_WRITE_MUTEX_H #define BU_READ_WRITE_MUTEX_H #include "bu/mutex.h" #include "bu/condition.h" namespace Bu { /** * Mutex designed for situations where overlapped reading is safe, but * overlapped writing isn't. There are many, many good examples of this * including most data structures, streams, etc. etc. * * Use this just like a normal mutex except that you use the * lockRead/unlockRead and lockWrite/unlockWrite functions depending on * weather the section of code your locking is reading data or changing * data. * * This particular mutex is designed so that while a read operation is * happening other read operations can also happen, but no write operations * can occur. While a write is happening, no other write or read operation * can continue. There is an extra feature to ensure writes get a chance * to complete, when a lockWrite is issued, all current read operations * continue, but future read operations block until the write is complete. */ class ReadWriteMutex { public: ReadWriteMutex(); virtual ~ReadWriteMutex(); /** * Lock the mutex for reading. Multiple code sections can hold a read * lock at the same time, but write locks will wait for all read locks * to be released before continuing. Read locks will also wait if * there is an active write lock. * * It is very important to not make any changes to your data within * a read lock. */ void lockRead(); /** * Release a read lock. */ void unlockRead(); /** * Lock the mutex for writing. Only one code section can have a write * lock at any given time. No code sections can be in a locked read * section while a write lock is held. When a write lock is requested * all following read locks will block until the write operation is * started, ensuring writes always get a chance to execute. * * Within a write locked code section feel free to change your data * and read your data. It is imparative to spend as little time as * possible in a write-locked section. */ void lockWrite(); /** * Release a write lock. */ void unlockWrite(); class ReadLocker { public: ReadLocker( ReadWriteMutex &m ) : m( m ) { m.lockRead(); } ~ReadLocker() { m.unlockRead(); } private: ReadWriteMutex &m; }; class WriteLocker { public: WriteLocker( ReadWriteMutex &m ) : m( m ) { m.lockWrite(); } ~WriteLocker() { m.unlockWrite(); } private: ReadWriteMutex &m; }; private: Bu::Mutex mRead; int iCounter; Bu::Mutex mWrite; Bu::Condition cWrite; bool bWantWrite; }; }; #endif