X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FSynchronized.h;h=0bbe788f0acbecac52c10a263f5ebd97c419ac96;hb=01c150d50546fe4c8e2cf0c3a5f1796967e47005;hp=94474037693c15608dadbc73035871cff8a41462;hpb=37f0ea5436571ecb77d1550991f02ba1b066ccec;p=folly.git diff --git a/folly/Synchronized.h b/folly/Synchronized.h index 94474037..0bbe788f 100644 --- a/folly/Synchronized.h +++ b/folly/Synchronized.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Facebook, Inc. + * Copyright 2015 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ #include #include #include -#include "folly/Preprocessor.h" -#include "folly/Traits.h" +#include +#include namespace folly { @@ -48,9 +48,12 @@ template struct HasLockUnlock { enum { value = IsOneOf::value }; }; @@ -95,6 +98,8 @@ acquireReadWrite(T& mutex) { mutex.lock(); } +// OSX and Cygwin don't have timed mutexes +#if !defined(__APPLE__) && !defined(__CYGWIN__) /** * Acquires a mutex for reading and writing with timeout by calling * .try_lock_for(). This applies to two of the std mutex classes as @@ -105,7 +110,12 @@ typename std::enable_if< IsOneOf::value, bool>::type acquireReadWrite(T& mutex, unsigned int milliseconds) { - return mutex.try_lock_for(std::chrono::milliseconds(milliseconds)); + // work around try_lock_for bug in some gcc versions, see + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54562 + return mutex.try_lock() + || (milliseconds > 0 && + mutex.try_lock_until(std::chrono::system_clock::now() + + std::chrono::milliseconds(milliseconds))); } /** @@ -121,6 +131,7 @@ acquireReadWrite(T& mutex, unsigned int milliseconds) { return mutex.timed_lock(boost::posix_time::milliseconds(milliseconds)); } +#endif // __APPLE__ /** * Releases a mutex previously acquired for reading by calling @@ -186,37 +197,56 @@ struct Synchronized { * constructor. */ Synchronized() = default; + + private: + static constexpr bool nxCopyCtor{ + std::is_nothrow_copy_constructible::value}; + static constexpr bool nxMoveCtor{ + std::is_nothrow_move_constructible::value}; + /** + * Helper constructors to enable Synchronized for + * non-default constructible types T. + * Guards are created in actual public constructors and are alive + * for the time required to construct the object + */ + template + Synchronized(const Synchronized& rhs, + const Guard& /*guard*/) noexcept(nxCopyCtor) + : datum_(rhs.datum_) {} + + template + Synchronized(Synchronized&& rhs, const Guard& /*guard*/) noexcept(nxMoveCtor) + : datum_(std::move(rhs.datum_)) {} + public: + /** * Copy constructor copies the data (with locking the source and * all) but does NOT copy the mutex. Doing so would result in * deadlocks. */ - Synchronized(const Synchronized& rhs) { - auto guard = rhs.operator->(); - datum_ = rhs.datum_; - } + Synchronized(const Synchronized& rhs) noexcept(nxCopyCtor) + : Synchronized(rhs, rhs.operator->()) {} /** * Move constructor moves the data (with locking the source and all) * but does not move the mutex. */ - Synchronized(Synchronized&& rhs) { - auto guard = rhs.operator->(); - datum_ = std::move(rhs.datum_); - } + Synchronized(Synchronized&& rhs) noexcept(nxMoveCtor) + : Synchronized(std::move(rhs), rhs.operator->()) {} /** * Constructor taking a datum as argument copies it. There is no * need to lock the constructing object. */ - explicit Synchronized(const T& rhs) : datum_(rhs) {} + explicit Synchronized(const T& rhs) noexcept(nxCopyCtor) : datum_(rhs) {} /** * Constructor taking a datum rvalue as argument moves it. Again, * there is no need to lock the constructing object. */ - explicit Synchronized(T && rhs) : datum_(std::move(rhs)) {} + explicit Synchronized(T&& rhs) noexcept(nxMoveCtor) + : datum_(std::move(rhs)) {} /** * The canonical assignment operator only assigns the data, NOT the @@ -224,7 +254,9 @@ struct Synchronized { * addresses. */ Synchronized& operator=(const Synchronized& rhs) { - if (this < *rhs) { + if (this == &rhs) { + // Self-assignment, pass. + } else if (this < &rhs) { auto guard1 = operator->(); auto guard2 = rhs.operator->(); datum_ = rhs.datum_; @@ -236,6 +268,26 @@ struct Synchronized { return *this; } + /** + * Move assignment operator, only assigns the data, NOT the + * mutex. It locks the two objects in ascending order of their + * addresses. + */ + Synchronized& operator=(Synchronized&& rhs) { + if (this == &rhs) { + // Self-assignment, pass. + } else if (this < &rhs) { + auto guard1 = operator->(); + auto guard2 = rhs.operator->(); + datum_ = std::move(rhs.datum_); + } else { + auto guard1 = rhs.operator->(); + auto guard2 = operator->(); + datum_ = std::move(rhs.datum_); + } + return *this; + } + /** * Lock object, assign datum. */ @@ -245,6 +297,15 @@ struct Synchronized { return *this; } + /** + * Lock object, move-assign datum. + */ + Synchronized& operator=(T&& rhs) { + auto guard = operator->(); + datum_ = std::move(rhs); + return *this; + } + /** * A LockedPtr lp keeps a modifiable (i.e. non-const) * Synchronized object locked for the duration of lp's @@ -275,7 +336,7 @@ struct Synchronized { return; } // Could not acquire the resource, pointer is null - parent_ = NULL; + parent_ = nullptr; } /** @@ -323,7 +384,7 @@ struct Synchronized { * SYNCHRONIZED below. */ T* operator->() { - return parent_ ? &parent_->datum_ : NULL; + return parent_ ? &parent_->datum_ : nullptr; } /** @@ -387,13 +448,13 @@ struct Synchronized { acquire(); } ConstLockedPtr(const Synchronized* parent, unsigned int milliseconds) { - if (parent->mutex_.timed_lock( + if (parent->mutex_.timed_lock_shared( boost::posix_time::milliseconds(milliseconds))) { parent_ = parent; return; } // Could not acquire the resource, pointer is null - parent_ = NULL; + parent_ = nullptr; } ConstLockedPtr& operator=(const ConstLockedPtr& rhs) { @@ -409,7 +470,7 @@ struct Synchronized { } const T* operator->() const { - return parent_ ? &parent_->datum_ : NULL; + return parent_ ? &parent_->datum_ : nullptr; } struct Unsynchronizer { @@ -515,7 +576,9 @@ struct Synchronized { } auto guard1 = operator->(); auto guard2 = rhs.operator->(); - datum_.swap(rhs.datum_); + + using std::swap; + swap(datum_, rhs.datum_); } /** @@ -524,7 +587,9 @@ struct Synchronized { */ void swap(T& rhs) { LockedPtr guard = operator->(); - datum_.swap(rhs); + + using std::swap; + swap(datum_, rhs); } /**