#ifndef READ_WRITE_MUTEX_HPP #define READ_WRITE_MUTEX_HPP // read_write_mutex.hpp // // (C) Copyright 2005 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include namespace boost { #define BOOST_RW_MUTEX_INIT {BOOST_ONCE_INIT} class read_write_mutex { public: boost::once_flag flag; void* active_pending; void* exclusive; long reader_count; long upgradeable_reader; private: struct initializer { read_write_mutex* self; initializer(read_write_mutex* self_): self(self_) {} void operator()() { self->active_pending=BOOST_CREATE_MUTEX(NULL,false,NULL); self->exclusive=BOOST_CREATE_MUTEX(NULL,false,NULL); self->reader_count=0; self->upgradeable_reader=0; } }; void initialize() { boost::call_once(initializer(this),flag); } void release_exclusive() { BOOST_RELEASE_MUTEX(exclusive); } void acquire_exclusive() { BOOST_WAIT_FOR_SINGLE_OBJECT(exclusive,BOOST_INFINITE); } void acquire_active_pending() { BOOST_WAIT_FOR_SINGLE_OBJECT(active_pending,BOOST_INFINITE); } void lock_acquired() { BOOST_RELEASE_MUTEX(active_pending); } public: ~read_write_mutex() { BOOST_CLOSE_HANDLE(exclusive); BOOST_CLOSE_HANDLE(active_pending); } void acquire_read_lock() { initialize(); acquire_active_pending(); acquire_exclusive(); BOOST_INTERLOCKED_INCREMENT(&reader_count); release_exclusive(); lock_acquired(); } void release_read_lock() { BOOST_INTERLOCKED_DECREMENT(&reader_count); } void acquire_write_lock() { initialize(); acquire_active_pending(); bool acquired=false; while(!acquired) { acquire_exclusive(); acquired=!BOOST_INTERLOCKED_COMPARE_EXCHANGE(&reader_count,0,0); if(!acquired) { release_exclusive(); } } lock_acquired(); } void release_write_lock() { release_exclusive(); } void acquire_upgradeable_lock() { initialize(); acquire_active_pending(); bool acquired=false; while(!acquired) { acquire_exclusive(); acquired=!BOOST_INTERLOCKED_COMPARE_EXCHANGE(&upgradeable_reader,1,0); if(acquired) { BOOST_INTERLOCKED_INCREMENT(&reader_count); } release_exclusive(); } lock_acquired(); } void release_upgradeable_lock() { BOOST_INTERLOCKED_EXCHANGE(&upgradeable_reader,0); release_read_lock(); } void upgrade_upgradeable_lock() { bool acquired=false; while(!acquired) { acquire_exclusive(); long const old_reader_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&reader_count,1,1); acquired=old_reader_count==1; if(!acquired) { release_exclusive(); } } BOOST_INTERLOCKED_DECREMENT(&reader_count); BOOST_INTERLOCKED_EXCHANGE(&upgradeable_reader,0); } }; class read_lock { read_write_mutex& mutex; public: read_lock(read_write_mutex& mutex_): mutex(mutex_) { mutex.acquire_read_lock(); } ~read_lock() { mutex.release_read_lock(); } }; class upgradeable_lock { friend class write_lock; read_write_mutex& mutex; bool upgraded; public: upgradeable_lock(read_write_mutex& mutex_): mutex(mutex_),upgraded(false) { mutex.acquire_upgradeable_lock(); } ~upgradeable_lock() { if(!upgraded) { mutex.release_upgradeable_lock(); } } }; class write_lock { read_write_mutex& mutex; public: write_lock(read_write_mutex& mutex_): mutex(mutex_) { mutex.acquire_write_lock(); } write_lock(upgradeable_lock& upgradeable): mutex(upgradeable.mutex) { mutex.upgrade_upgradeable_lock(); upgradeable.upgraded=true; } ~write_lock() { mutex.release_write_lock(); } }; } #endif