1 /*************************************************************************** 2 * include/stxxl/bits/common/mutex.h 3 * 4 * Part of the STXXL. See http://stxxl.sourceforge.net 5 * 6 * Copyright (C) 2002 Roman Dementiev <dementiev@mpi-sb.mpg.de> 7 * Copyright (C) 2008 Andreas Beckmann <beckmann@cs.uni-frankfurt.de> 8 * Copyright (C) 2013 Timo Bingmann <tb@panthema.net> 9 * 10 * Distributed under the Boost Software License, Version 1.0. 11 * (See accompanying file LICENSE_1_0.txt or copy at 12 * http://www.boost.org/LICENSE_1_0.txt) 13 **************************************************************************/ 14 15 #ifndef STXXL_COMMON_MUTEX_HEADER 16 #define STXXL_COMMON_MUTEX_HEADER 17 18 #include <stxxl/bits/config.h> 19 #include <stxxl/bits/namespace.h> 20 21 #if STXXL_STD_THREADS 22 #include <mutex> 23 #elif STXXL_BOOST_THREADS 24 #include <boost/thread/mutex.hpp> 25 #elif STXXL_POSIX_THREADS 26 #include <pthread.h> 27 28 #include <stxxl/bits/noncopyable.h> 29 #include <stxxl/bits/common/error_handling.h> 30 #else 31 #error "Thread implementation not detected." 32 #endif 33 34 STXXL_BEGIN_NAMESPACE 35 36 #if STXXL_STD_THREADS 37 38 typedef std::mutex mutex; 39 40 #elif STXXL_BOOST_THREADS 41 42 typedef boost::mutex mutex; 43 44 #elif STXXL_POSIX_THREADS 45 46 class mutex : private noncopyable 47 { 48 //! mutex handle 49 pthread_mutex_t m_mutex; 50 51 public: 52 //! construct unlocked mutex 53 mutex() 54 { 55 STXXL_CHECK_PTHREAD_CALL(pthread_mutex_init(&m_mutex, NULL)); 56 } 57 //! destroy mutex handle 58 ~mutex() 59 { 60 // try simple delete first 61 int res = pthread_mutex_destroy(&m_mutex); 62 if (res == 0) return; 63 64 // try to lock and unlock mutex 65 res = pthread_mutex_trylock(&m_mutex); 66 67 if (res == 0 || res == EBUSY) { 68 STXXL_CHECK_PTHREAD_CALL(pthread_mutex_unlock(&m_mutex)); 69 } else { 70 STXXL_THROW_ERRNO2(resource_error, "pthread_mutex_trylock() failed", res); 71 } 72 73 STXXL_CHECK_PTHREAD_CALL(pthread_mutex_destroy(&m_mutex)); 74 } 75 //! lock mutex, may block 76 void lock() 77 { 78 STXXL_CHECK_PTHREAD_CALL(pthread_mutex_lock(&m_mutex)); 79 } 80 //! unlock mutex 81 void unlock() 82 { 83 STXXL_CHECK_PTHREAD_CALL(pthread_mutex_unlock(&m_mutex)); 84 } 85 //! return platform specific handle 86 pthread_mutex_t & native_handle() 87 { 88 return m_mutex; 89 } 90 }; 91 92 #endif 93 94 #if STXXL_STD_THREADS 95 96 typedef std::unique_lock<std::mutex> scoped_mutex_lock; 97 98 #elif STXXL_BOOST_THREADS 99 100 typedef boost::mutex::scoped_lock scoped_mutex_lock; 101 102 #else 103 104 //! Aquire a lock that's valid until the end of scope. 105 class scoped_mutex_lock 106 { 107 //! mutex reference 108 mutex& m_mutex; 109 110 //! marker if already unlocked by this thread (needs no synchronization) 111 bool is_locked; 112 113 public: 114 //! lock mutex scoped_mutex_lock(mutex & m)115 scoped_mutex_lock(mutex& m) 116 : m_mutex(m), is_locked(true) 117 { 118 m_mutex.lock(); 119 } 120 //! unlock mutex hold when object goes out of scope. ~scoped_mutex_lock()121 ~scoped_mutex_lock() 122 { 123 unlock(); 124 } 125 //! unlock mutex hold prematurely unlock()126 void unlock() 127 { 128 if (is_locked) { 129 is_locked = false; 130 m_mutex.unlock(); 131 } 132 } 133 //! return platform specific handle native_handle()134 pthread_mutex_t & native_handle() 135 { 136 return m_mutex.native_handle(); 137 } 138 }; 139 140 #endif 141 142 STXXL_END_NAMESPACE 143 144 #endif // !STXXL_COMMON_MUTEX_HEADER 145