Index: boost/thread/pthread/shared_mutex.hpp =================================================================== --- boost/thread/pthread/shared_mutex.hpp (revision 83553) +++ boost/thread/pthread/shared_mutex.hpp (working copy) @@ -38,6 +38,25 @@ upgrade(false), exclusive_waiting_blocked(false) {} + + state_data (const state_data & rhs) : + shared_count(rhs.shared_count), + exclusive(rhs.exclusive), + upgrade(rhs.upgrade), + exclusive_waiting_blocked(rhs.exclusive_waiting_blocked) + {} + + state_data & operator = (const state_data & rhs) + { + if (this != &rhs) { + shared_count = rhs.shared_count; + exclusive = rhs.exclusive; + upgrade = rhs.upgrade; + exclusive_waiting_blocked = rhs.exclusive_waiting_blocked; + } + + return *this; + } void assert_free() const { @@ -155,12 +174,10 @@ }; - state_data state; boost::mutex state_change; boost::condition_variable shared_cond; boost::condition_variable exclusive_cond; - boost::condition_variable upgrade_cond; void release_waiters() { @@ -261,23 +278,15 @@ boost::unique_lock lk(state_change); state.assert_lock_shared(); state.unlock_shared(); - if (! state.more_shared()) + + if (!state.more_shared()) { - if (state.upgrade) - { - // As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared() - // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified. - state.upgrade=false; - state.exclusive=true; - lk.unlock(); - upgrade_cond.notify_one(); - } - else - { - state.exclusive_waiting_blocked=false; - lk.unlock(); - } - release_waiters(); + state.exclusive_waiting_blocked=false; + exclusive_cond.notify_one(); + } else if (state.upgrade && state.exclusive_waiting_blocked) + { + // unlock_upgrade_and_lock currently waiting + exclusive_cond.notify_one(); } } @@ -489,7 +498,7 @@ } } - // Upgrade <-> Exclusive + // Upgrade -> Exclusive void unlock_upgrade_and_lock() { #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS @@ -497,13 +506,22 @@ #endif boost::unique_lock lk(state_change); state.assert_lock_upgraded(); - state.unlock_shared(); - while (state.more_shared()) - { - upgrade_cond.wait(lk); + + for (;;) { + // modify a copy of state to prevent side-effects during wait + state_data tmp = state; // copy state + tmp.unlock_upgrade(); + + if (!tmp.can_lock()) { + state.exclusive_waiting_blocked = true; // intentionally on state and not tmp + exclusive_cond.wait(lk); + } else { + tmp.lock(); + state = tmp; // commit change + break; + } } - state.upgrade=false; - state.exclusive=true; + state.assert_locked(); }