#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 #include #define BOOST_INTERLOCKED_READ(x) BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0) namespace boost { #define BOOST_RW_MUTEX_INIT {BOOST_ONCE_INIT} namespace detail { class lightweight_mutex { public: long lock_flag; void* lock_sem; void initialize() { lock_flag=0; lock_sem=CreateSemaphore(NULL,0,1,NULL); } ~lightweight_mutex() { CloseHandle(lock_sem); } void lock() { while(BOOST_INTERLOCKED_COMPARE_EXCHANGE(&lock_flag,1,0)) { BOOST_WAIT_FOR_SINGLE_OBJECT(lock_sem,BOOST_INFINITE); } } void unlock() { BOOST_INTERLOCKED_EXCHANGE(&lock_flag,0); ReleaseSemaphore(lock_sem,1,NULL); } }; } class read_write_mutex { static const long unlocked_state=0; static const long reading_state=1; static const long writing_state=2; static const long upgrading_state=3; static const long reading_with_upgradeable_state=4; static const long acquiring_reading_state=5; static const long releasing_reading_state=6; static const long releasing_reading_with_upgradeable_state=7; public: boost::once_flag flag; detail::lightweight_mutex active_pending; detail::lightweight_mutex state_change_gate; long mutex_state_flag; void* mutex_state_sem; long reader_count; long waiting_count; private: struct initializer { read_write_mutex* self; initializer(read_write_mutex* self_): self(self_) {} void operator()() { self->active_pending.initialize(); self->state_change_gate.initialize(); self->mutex_state_sem=CreateSemaphore(NULL,0,LONG_MAX,NULL); self->reader_count=0; self->mutex_state_flag=unlocked_state; self->waiting_count=0; } }; void initialize() { boost::call_once(initializer(this),flag); } void release_mutex_state_sem() { state_change_gate.lock(); long const count_to_unlock=BOOST_INTERLOCKED_READ(&waiting_count); if(count_to_unlock) { ReleaseSemaphore(mutex_state_sem,count_to_unlock,NULL); } else { state_change_gate.unlock(); } } void acquire_mutex_state_sem() { long const waiter_count=BOOST_INTERLOCKED_INCREMENT(&waiting_count); state_change_gate.unlock(); BOOST_WAIT_FOR_SINGLE_OBJECT(mutex_state_sem,BOOST_INFINITE); long const remaining_waiters=BOOST_INTERLOCKED_DECREMENT(&waiting_count); if(!remaining_waiters) { state_change_gate.unlock(); } } template long enter_new_state(long const (&old_states)[array_size],long new_state) { bool blocked=false; while(true) { if(blocked) { state_change_gate.lock(); } for(unsigned i=0;i