diff --git a/boost/thread/pthread/shared_mutex.hpp b/boost/thread/pthread/shared_mutex.hpp index 458d6c8..9d527db 100644 --- a/boost/thread/pthread/shared_mutex.hpp +++ b/boost/thread/pthread/shared_mutex.hpp @@ -24,6 +24,11 @@ #include +#if defined BOOST_THREAD_USE_PTHREAD_RWLOCKS +#include +#include +#endif + namespace boost { class shared_mutex @@ -162,6 +167,10 @@ namespace boost boost::condition_variable exclusive_cond; boost::condition_variable upgrade_cond; +#if defined BOOST_THREAD_PTHREAD_USE_RWLOCKS + pthread_rwlock_t rw_lock; +#endif + void release_waiters() { exclusive_cond.notify_one(); @@ -174,14 +183,62 @@ namespace boost shared_mutex() { +#if defined BOOST_THREAD_PTHREAD_USE_RWLOCKS + int ret = 0; +#if defined(__linux__) + // Linux rwlocks are by default writer-starving + pthread_rwlockattr_t attr; + ret = pthread_rwlockattr_init(&attr); + if (ret) + { + throw std::runtime_error("pthread_rwlockattr_init faild"); + } + ret = pthread_rwlockattr_setkind_np(&attr, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + if (ret) + { + throw std::runtime_error("pthread_rwlockattr_setkind_np failed"); + } + ret = pthread_rwlock_init(&lock_, &attr); + if (ret) + { + throw std::runtime_error("pthread_rwlock_init failed"); + } + ret = pthread_rwlockattr_destroy(&attr); + if (ret) + { + throw std::runtime_error("pthread_rwlockattr_destroy failed"); + } +#else + ret = pthread_rwlock_init(&lock_, NULL); + if (ret) + { + throw std::runtime_error("pthread_rwlock_init failed"); + } +#endif +#endif } ~shared_mutex() { +#if defined BOOST_THREAD_PTHREAD_USE_RWLOCKS + int ret = pthread_rwlock_destroy(&lock_); + if (ret) + { + throw std::runtime_error("pthread_rwlock_destroy failed"); + } +#endif } void lock_shared() { +#if defined BOOST_THREAD_USE_PTHREAD_RWLOCKS + int ret = pthread_rwlock_rdlock(&rw_lock); + if (ret) + { + throw std::runtime_error("pthread_rwlock_rdlock failed"); + } +#else #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; #endif @@ -191,10 +248,23 @@ namespace boost shared_cond.wait(lk); } state.lock_shared(); +#endif } bool try_lock_shared() { +#if definet BOOST_THREAD_USE_PTHREAD_RWLOCKS + int ret = pthread_rwlock_tryrdlock(&rw_lock); + if (!ret) + { + return true; + } + else if (ret == EBUSY) + { + return false; + } + throw std::runtime_error("pthread_rwlock_tryrdlock failed"); +#else boost::unique_lock lk(state_change); if(!state.can_lock_shared()) @@ -203,6 +273,7 @@ namespace boost } state.lock_shared(); return true; +#endif } #if defined BOOST_THREAD_USES_DATETIME @@ -258,6 +329,13 @@ namespace boost #endif void unlock_shared() { +#if defined BOOST_THREAD_USE_PTHREAD_RWLOCKS + int ret = pthread_rwlock_unlock(&rw_lock); + if (ret) + { + throw std::runtime_error("pthread_rwlock_unlock failed"); + } +#else boost::unique_lock lk(state_change); state.assert_lock_shared(); state.unlock_shared(); @@ -279,10 +357,18 @@ namespace boost } release_waiters(); } +#endif } void lock() { +#if defined BOOST_THREAD_USE_PTHREAD_RWLOCKS + int ret = pthread_rwlock_wrlock(&rw_lock); + if (ret) + { + throw std::runtime_error("pthread_rwlock_wrlock failed"); + } +#else #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; #endif @@ -294,6 +380,7 @@ namespace boost exclusive_cond.wait(lk); } state.exclusive=true; +#endif } #if defined BOOST_THREAD_USES_DATETIME @@ -363,6 +450,18 @@ namespace boost bool try_lock() { +#if defined BOOST_THREAD_USE_PTHREAD_RWLOCKS + int ret = pthread_rwlock_trywrlock(&rw_lock); + if (!ret) + { + return true; + } + else if (ret == EBUSY) + { + return false; + } + throw std::runtime_error("pthread_rwlock_trywrlock failed"); +#else boost::unique_lock lk(state_change); if(state.shared_count || state.exclusive) @@ -374,17 +473,25 @@ namespace boost state.exclusive=true; return true; } - +#endif } void unlock() { +#if defined BOOST_THREAD_USE_PTHREAD_RWLOCKS + int ret = pthread_rwlock_unlock(&rw_lock); + if (ret) + { + throw std::runtime_error("pthread_rwlock_unlock failed"); + } +#else boost::unique_lock lk(state_change); state.assert_locked(); state.exclusive=false; state.exclusive_waiting_blocked=false; state.assert_free(); release_waiters(); +#endif } void lock_upgrade()