#include <mutex>
#include <boost/thread.hpp>
#include <folly/Preprocessor.h>
+#include <folly/SharedMutex.h>
#include <folly/Traits.h>
namespace folly {
*/
template <class T>
struct HasLockUnlock {
- enum { value = IsOneOf<T,
- std::mutex, std::recursive_mutex,
- boost::mutex, boost::recursive_mutex, boost::shared_mutex
+ enum { value = IsOneOf<T
+ , std::mutex
+ , std::recursive_mutex
+ , boost::mutex
+ , boost::recursive_mutex
+ , boost::shared_mutex
#if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
- ,std::timed_mutex, std::recursive_timed_mutex,
- boost::timed_mutex, boost::recursive_timed_mutex
+ , std::timed_mutex
+ , std::recursive_timed_mutex
+ , boost::timed_mutex
+ , boost::recursive_timed_mutex
#endif
- >::value };
+ >::value };
};
/**
- * Acquires a mutex for reading by calling .lock(). The exception is
- * boost::shared_mutex, which has a special read-lock primitive called
- * .lock_shared().
+ * Yields true iff T has .lock_shared() and .unlock_shared() member functions.
+ * This is done by simply enumerating the mutexes with this interface.
*/
template <class T>
-typename std::enable_if<
- HasLockUnlock<T>::value && !std::is_same<T, boost::shared_mutex>::value>::type
-acquireRead(T& mutex) {
- mutex.lock();
-}
+struct HasLockSharedUnlockShared {
+ enum { value = IsOneOf<T
+ , boost::shared_mutex
+ >::value };
+};
/**
- * Special case for boost::shared_mutex.
+ * Acquires a mutex for reading by calling .lock().
+ *
+ * This variant is not appropriate for shared mutexes.
*/
template <class T>
-typename std::enable_if<std::is_same<T, boost::shared_mutex>::value>::type
+typename std::enable_if<
+ HasLockUnlock<T>::value && !HasLockSharedUnlockShared<T>::value>::type
acquireRead(T& mutex) {
- mutex.lock_shared();
+ mutex.lock();
}
/**
- * Acquires a mutex for reading with timeout by calling .timed_lock(). This
- * applies to three of the boost mutex classes as enumerated below.
+ * Acquires a mutex for reading by calling .lock_shared().
+ *
+ * This variant is not appropriate for nonshared mutexes.
*/
template <class T>
-typename std::enable_if<std::is_same<T, boost::shared_mutex>::value, bool>::type
-acquireRead(T& mutex,
- unsigned int milliseconds) {
- return mutex.timed_lock_shared(boost::posix_time::milliseconds(milliseconds));
+typename std::enable_if<HasLockSharedUnlockShared<T>::value>::type
+acquireRead(T& mutex) {
+ mutex.lock_shared();
}
/**
}
#if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
+/**
+ * Acquires a mutex for reading by calling .try_lock_shared_for(). This applies
+ * to boost::shared_mutex.
+ */
+template <class T>
+typename std::enable_if<
+ IsOneOf<T
+ , boost::shared_mutex
+ >::value, bool>::type
+acquireRead(T& mutex,
+ unsigned int milliseconds) {
+ return mutex.try_lock_shared_for(boost::chrono::milliseconds(milliseconds));
+}
+
/**
* Acquires a mutex for reading and writing with timeout by calling
* .try_lock_for(). This applies to two of the std mutex classes as
*/
template <class T>
typename std::enable_if<
- IsOneOf<T, std::timed_mutex, std::recursive_timed_mutex>::value, bool>::type
+ IsOneOf<T
+ , std::timed_mutex
+ , std::recursive_timed_mutex
+ >::value, bool>::type
acquireReadWrite(T& mutex,
unsigned int milliseconds) {
// work around try_lock_for bug in some gcc versions, see
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54562
+ // TODO: Fixed in gcc-4.9.0.
return mutex.try_lock()
|| (milliseconds > 0 &&
mutex.try_lock_until(std::chrono::system_clock::now() +
/**
* Acquires a mutex for reading and writing with timeout by calling
- * .timed_lock(). This applies to three of the boost mutex classes as
+ * .try_lock_for(). This applies to three of the boost mutex classes as
* enumerated below.
*/
template <class T>
typename std::enable_if<
- IsOneOf<T, boost::shared_mutex, boost::timed_mutex,
- boost::recursive_timed_mutex>::value, bool>::type
+ IsOneOf<T
+ , boost::shared_mutex
+ , boost::timed_mutex
+ , boost::recursive_timed_mutex
+ >::value, bool>::type
acquireReadWrite(T& mutex,
unsigned int milliseconds) {
- return mutex.timed_lock(boost::posix_time::milliseconds(milliseconds));
+ return mutex.try_lock_for(boost::chrono::milliseconds(milliseconds));
}
#endif // FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
*/
template <class T>
typename std::enable_if<
- HasLockUnlock<T>::value && !std::is_same<T, boost::shared_mutex>::value>::type
+ HasLockUnlock<T>::value && !HasLockSharedUnlockShared<T>::value>::type
releaseRead(T& mutex) {
mutex.unlock();
}
* Special case for boost::shared_mutex.
*/
template <class T>
-typename std::enable_if<std::is_same<T, boost::shared_mutex>::value>::type
+typename std::enable_if<HasLockSharedUnlockShared<T>::value>::type
releaseRead(T& mutex) {
mutex.unlock_shared();
}
* refer to the namespace detail below, which implements the
* primitives for mutexes in std and boost.
*/
-template <class T, class Mutex = boost::shared_mutex>
+template <class T, class Mutex = SharedMutex>
struct Synchronized {
/**
* Default constructor leaves both members call their own default
explicit Synchronized(T&& rhs) noexcept(nxMoveCtor)
: datum_(std::move(rhs)) {}
+ /**
+ * Lets you construct non-movable types in-place. Use the constexpr
+ * instance `construct_in_place` as the first argument.
+ */
+ template <typename... Args>
+ explicit Synchronized(construct_in_place_t, Args&&... args)
+ : datum_(std::forward<Args>(args)...) {}
+
/**
* The canonical assignment operator only assigns the data, NOT the
* mutex. It locks the two objects in ascending order of their
acquire();
}
ConstLockedPtr(const Synchronized* parent, unsigned int milliseconds) {
- if (parent->mutex_.timed_lock_shared(
- boost::posix_time::milliseconds(milliseconds))) {
+ using namespace detail;
+ if (acquireRead(
+ parent->mutex_,
+ milliseconds)) {
parent_ = parent;
return;
}
* examples.
*/
#define SYNCHRONIZED(...) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wshadow\"") \
if (bool SYNCHRONIZED_state = false) {} else \
for (auto SYNCHRONIZED_lockedPtr = \
(FB_ARG_2_OR_1(__VA_ARGS__)).operator->(); \
!SYNCHRONIZED_state; SYNCHRONIZED_state = true) \
for (auto& FB_ARG_1(__VA_ARGS__) = \
*SYNCHRONIZED_lockedPtr.operator->(); \
- !SYNCHRONIZED_state; SYNCHRONIZED_state = true)
+ !SYNCHRONIZED_state; SYNCHRONIZED_state = true) \
+ _Pragma("GCC diagnostic pop")
#define TIMED_SYNCHRONIZED(timeout, ...) \
if (bool SYNCHRONIZED_state = false) {} else \
for (decltype(SYNCHRONIZED_lockedPtr.typeHackDoNotUse()) \
SYNCHRONIZED_state3(&SYNCHRONIZED_lockedPtr); \
!SYNCHRONIZED_state; SYNCHRONIZED_state = true) \
- for (auto name = *SYNCHRONIZED_state3.operator->(); \
+ for (auto& name = *SYNCHRONIZED_state3.operator->(); \
!SYNCHRONIZED_state; SYNCHRONIZED_state = true)
/**