36 #include <glog/logging.h> 41 #include <type_traits> 46 template <
class LockedType,
class Mutex,
class LockPolicy>
48 template <
class LockedType,
class LockPolicy>
62 template <
class Mutex>
74 template <
class Sub
class, detail::MutexLevel level>
83 template <
class Sub
class>
104 return LockedPtr(static_cast<Subclass*>(
this));
144 template <
class Rep,
class Period>
146 return LockedPtr(static_cast<Subclass*>(
this), timeout);
156 template <
class Rep,
class Period>
158 const std::chrono::duration<Rep, Period>& timeout)
const {
159 return ConstLockedPtr(static_cast<const Subclass*>(
this), timeout);
176 template <
class Function>
178 return function(*
wlock());
190 template <
class Function>
192 return function(
wlock());
201 template <
class Function>
203 return function(*
rlock());
206 template <
class Function>
208 return function(
rlock());
219 template <
class Sub
class>
259 template <
class Rep,
class Period>
284 template <
class Function>
286 return function(*
ulock());
301 template <
class Function>
303 return function(
ulock());
313 template <
class Sub
class>
329 return LockedPtr(static_cast<Subclass*>(
this));
358 template <
class Rep,
class Period>
360 return LockedPtr(static_cast<Subclass*>(
this), timeout);
367 template <
class Rep,
class Period>
369 return ConstLockedPtr(static_cast<const Subclass*>(
this), timeout);
386 template <
class Function>
388 return function(*
lock());
390 template <
class Function>
392 return function(*
lock());
404 template <
class Function>
406 return function(
lock());
408 template <
class Function>
410 return function(
lock());
437 template <
class T,
class Mutex = SharedMutex>
439 Synchronized<T, Mutex>,
440 MutexLevelValue<Mutex>::value> {
444 static constexpr
bool nxCopyCtor{
446 static constexpr
bool nxMoveCtor{
450 class NonImplementedType;
512 template <
typename...
Args>
514 : datum_(
std::forward<
Args>(args)...) {}
520 template <
typename... DatumArgs,
typename... MutexArgs>
522 std::piecewise_construct_t,
523 std::tuple<DatumArgs...> datumArgs,
524 std::tuple<MutexArgs...> mutexArgs)
549 NonImplementedType>::
type rhs) {
550 return *
this = rhs.
copy();
571 if (&datum_ != &rhs) {
572 auto guard = operator->();
582 if (&datum_ != &
rhs) {
583 auto guard = operator->();
607 template <
class Rep,
class Period>
611 template <
class Rep,
class Period>
613 const std::chrono::duration<Rep, Period>& timeout)
const {
626 template <
class Rep,
class Period>
628 const std::chrono::duration<Rep, Period>& timeout)
const {
664 return LockedPtr(
this, std::chrono::milliseconds(milliseconds));
676 return ConstLockedPtr(
this, std::chrono::milliseconds(milliseconds));
689 return rhs.
swap(*
this);
691 auto guard1 = operator->();
692 auto guard2 = rhs.operator->();
735 template <
class LockedType,
class MutexType,
class LockPolicy>
737 template <
class LockedType,
class LockPolicy>
749 : datum_(rhs.datum_) {}
756 typename... DatumArgs,
757 typename... MutexArgs,
758 std::size_t... IndicesOne,
759 std::size_t... IndicesTwo>
761 std::piecewise_construct_t,
762 std::tuple<DatumArgs...> datumArgs,
763 std::tuple<MutexArgs...> mutexArgs,
766 : datum_{std::get<IndicesOne>(
std::move(datumArgs))...},
774 template <
class SynchronizedType,
class LockPolicy>
782 template <
class SynchronizedType>
785 typename SynchronizedType::DataType
const,
786 typename SynchronizedType::DataType>
::type;
791 template <
class SynchronizedType>
793 std::is_const<SynchronizedType>::value,
794 typename SynchronizedType::ConstLockedPtr,
795 typename SynchronizedType::LockedPtr>
::type;
800 typename TryLockFunc,
806 template <
typename LockFuncType,
typename TryLockFuncType,
typename... As>
809 LockFuncType&& lockFunc,
810 TryLockFuncType tryLockFunc,
813 lockFunc_{std::forward<LockFuncType>(lockFunc)},
814 tryLockFunc_{std::forward<TryLockFuncType>(tryLockFunc)},
815 args_{std::forward<As>(
as)...} {}
818 auto args = std::tuple<
const Args&...>{args_};
819 return apply(lockFunc_, std::tuple_cat(std::tie(
synchronized), args));
822 return tryLockFunc_(
synchronized);
826 Synchronized&
synchronized;
835 typename TryLockFunc,
840 TryLockFunc&& tryLockFunc,
842 using LockFuncType = std::decay_t<LockFunc>;
843 using TryLockFuncType = std::decay_t<TryLockFunc>;
848 std::decay_t<Args>...>{
synchronized,
849 std::forward<LockFunc>(lockFunc),
850 std::forward<TryLockFunc>(tryLockFunc),
851 std::forward<Args>(args)...};
874 auto lockers = std::forward_as_tuple(lockersIn...);
880 std::get<0>(lockedPtrs) = std::get<0>(lockers).lock();
881 auto indexLocked = 0;
884 auto couldLockAll =
true;
886 for_each(lockers, [&](
auto& locker,
auto index) {
888 if (index != indexLocked) {
889 auto lockedPtr = locker.tryLock();
904 fetch(lockedPtrs, index) = locker.lock();
906 couldLockAll =
false;
928 [](
auto&
s,
auto&&...
a) {
929 return s.wlock(std::forward<decltype(
a)>(
a)...);
931 [](
auto&
s) {
return s.tryWLock(); },
932 std::forward<Args>(args)...);
938 [](
auto&
s,
auto&&...
a) {
939 return s.rlock(std::forward<decltype(
a)>(
a)...);
941 [](
auto&
s) {
return s.tryRLock(); },
942 std::forward<Args>(args)...);
948 [](
auto&
s,
auto&&...
a) {
949 return s.ulock(std::forward<decltype(
a)>(
a)...);
951 [](
auto&
s) {
return s.tryULock(); },
952 std::forward<Args>(args)...);
958 [](
auto&
s,
auto&&...
a) {
959 return s.lock(std::forward<decltype(
a)>(
a)...);
961 [](
auto&
s) {
return s.tryLock(); },
962 std::forward<Args>(args)...);
985 template <
class SynchronizedType,
class Mutex,
class LockPolicy>
994 template <
typename S,
typename L>
996 template <
typename S,
typename M,
typename L>
1004 LockPolicy::unlock(parent_->mutex_);
1017 DCHECK(parent_ !=
nullptr);
1018 LockPolicy::unlock(parent_->mutex_);
1030 template <
class Rep,
class Period>
1032 SynchronizedType*
parent,
1033 const std::chrono::duration<Rep, Period>& timeout) {
1034 if (LockPolicy::try_lock_for(parent->mutex_, timeout)) {
1041 assignImpl(*
this,
rhs);
1057 template <
typename LockPolicyType>
1061 template <
typename LockPolicyType>
1064 assignImpl(*
this,
rhs);
1071 template <
typename LockPolicyLhs,
typename LockPolicyRhs>
1076 LockPolicy::unlock(lhs.parent_->mutex_);
1096 DCHECK(parent_ !=
nullptr);
1099 LockPolicy::unlock(
current->mutex_);
1103 DCHECK(parent_ ==
nullptr);
1108 SynchronizedType* parent_ =
nullptr;
1118 template <
class SynchronizedType,
class LockPolicy>
1127 template <
typename S,
typename L>
1129 template <
typename S,
typename M,
typename L>
1143 assignImpl(*
this,
rhs);
1153 template <
typename LockPolicyType>
1157 parent_{
exchange(other.parent_,
nullptr)} {}
1158 template <
typename LockPolicyType>
1162 assignImpl(*
this,
rhs);
1169 template <
typename LockPolicyLhs,
typename LockPolicyRhs>
1201 DCHECK(parent_ !=
nullptr);
1209 : lock_{parent->mutex_, std::adopt_lock}, parent_{
parent} {
1218 std::pair<std::unique_lock<std::mutex>, SynchronizedType*>;
1225 DCHECK(parent_ !=
nullptr);
1228 data.first.unlock();
1234 parent_ =
data.second;
1240 SynchronizedType* parent_ =
nullptr;
1246 template <
class SynchronizedType,
class LockPolicy>
1286 template <
class SynchronizedType,
class LockPolicy>
1289 typename SynchronizedType::MutexType,
1294 typename SynchronizedType::MutexType,
1301 template <
typename LockPolicyOther>
1303 typename LockPolicy::UnlockPolicy,
1307 template <
typename SynchronizedTypeOther,
typename LockPolicyOther>
1336 template <
class Rep,
class Period>
1338 SynchronizedType*
parent,
1339 const std::chrono::duration<Rep, Period>& timeout)
1340 :
Base(parent, timeout) {}
1347 typename LockPolicyType,
1357 typename LockPolicyType,
1358 EnableIfSameUnlockPolicy<LockPolicyType>* =
nullptr>
1387 return this->parent_ ==
nullptr;
1395 explicit operator bool()
const {
1396 return this->parent_ !=
nullptr;
1405 return &this->parent_->datum_;
1414 return this->parent_->datum_;
1437 typename SyncType = SynchronizedType,
1438 typename =
typename std::enable_if<
1451 typename SyncType = SynchronizedType,
1452 typename =
typename std::enable_if<
1465 typename SyncType = SynchronizedType,
1466 typename =
typename std::enable_if<
1479 typename SyncType = SynchronizedType,
1480 typename =
typename std::enable_if<
1518 template <
typename D,
typename M,
typename...
Args>
1520 return detail::wlock(
synchronized, std::forward<Args>(args)...);
1524 return detail::rlock(
synchronized, std::forward<Args>(args)...);
1526 template <
typename D,
typename M,
typename...
Args>
1528 return detail::ulock(
synchronized, std::forward<Args>(args)...);
1530 template <
typename D,
typename M,
typename...
Args>
1532 return detail::lock(
synchronized, std::forward<Args>(args)...);
1534 template <
typename D,
typename M,
typename...
Args>
1536 return detail::lock(
synchronized, std::forward<Args>(args)...);
1552 template <
typename Func,
typename... SynchronizedLockers>
1555 std::forward<Func>(func),
1556 lock(std::forward<SynchronizedLockers>(lockers)...));
1591 template <
typename LockableOne,
typename LockableTwo,
typename... Lockables>
1592 void lock(LockableOne& one, LockableTwo& two, Lockables&... lockables) {
1593 auto locker = [](
auto& lockable) {
1594 using Lockable = std::remove_reference_t<decltype(lockable)>;
1597 [](
auto& l) {
return std::unique_lock<Lockable>{l}; },
1599 auto lock = std::unique_lock<Lockable>{l, std::defer_lock};
1604 auto locks =
lock(locker(one), locker(two), locker(lockables)...);
1624 template <
class Sync1,
class Sync2>
1627 if (static_cast<const void*>(&l1) < static_cast<const void*>(&l2)) {
1628 auto p1 = l1.contextualLock();
1629 auto p2 = l2.contextualLock();
1632 auto p2 = l2.contextualLock();
1633 auto p1 = l1.contextualLock();
1642 template <
class Sync1,
class Sync2>
1646 return {
std::move(std::get<0>(lockedPtrs)),
1655 template <
class T,
class M>
1667 #define SYNCHRONIZED_VAR(var) FB_CONCATENATE(SYNCHRONIZED_##var##_, __LINE__) 1686 #define SYNCHRONIZED(...) \ 1687 FOLLY_PUSH_WARNING \ 1688 FOLLY_GNU_DISABLE_WARNING("-Wshadow") \ 1689 FOLLY_MSVC_DISABLE_WARNING(4189) \ 1690 FOLLY_MSVC_DISABLE_WARNING(4456) \ 1691 FOLLY_MSVC_DISABLE_WARNING(4457) \ 1692 FOLLY_MSVC_DISABLE_WARNING(4458) \ 1693 FOLLY_MSVC_DISABLE_WARNING(4459) \ 1694 FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS \ 1695 if (bool SYNCHRONIZED_VAR(state) = false) { \ 1697 for (auto SYNCHRONIZED_VAR(lockedPtr) = \ 1698 (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).operator->(); \ 1699 !SYNCHRONIZED_VAR(state); \ 1700 SYNCHRONIZED_VAR(state) = true) \ 1701 for (auto& FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) = \ 1702 *SYNCHRONIZED_VAR(lockedPtr).operator->(); \ 1703 !SYNCHRONIZED_VAR(state); \ 1704 SYNCHRONIZED_VAR(state) = true) \ 1707 #define TIMED_SYNCHRONIZED(timeout, ...) \ 1708 if (bool SYNCHRONIZED_VAR(state) = false) { \ 1710 for (auto SYNCHRONIZED_VAR(lockedPtr) = \ 1711 (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).timedAcquire(timeout); \ 1712 !SYNCHRONIZED_VAR(state); \ 1713 SYNCHRONIZED_VAR(state) = true) \ 1714 for (auto FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) = \ 1715 (!SYNCHRONIZED_VAR(lockedPtr) \ 1717 : SYNCHRONIZED_VAR(lockedPtr).operator->()); \ 1718 !SYNCHRONIZED_VAR(state); \ 1719 SYNCHRONIZED_VAR(state) = true) 1724 #define SYNCHRONIZED_CONST(...) \ 1726 FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)), \ 1727 as_const(FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__)))) 1732 #define TIMED_SYNCHRONIZED_CONST(timeout, ...) \ 1733 TIMED_SYNCHRONIZED( \ 1735 FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)), \ 1736 as_const(FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__)))) 1743 #define SYNCHRONIZED_DUAL(n1, e1, n2, e2) \ 1744 if (bool SYNCHRONIZED_VAR(state) = false) { \ 1746 for (auto SYNCHRONIZED_VAR(ptrs) = acquireLockedPair(e1, e2); \ 1747 !SYNCHRONIZED_VAR(state); \ 1748 SYNCHRONIZED_VAR(state) = true) \ 1749 for (auto& n1 = *SYNCHRONIZED_VAR(ptrs).first; !SYNCHRONIZED_VAR(state); \ 1750 SYNCHRONIZED_VAR(state) = true) \ 1751 for (auto& n2 = *SYNCHRONIZED_VAR(ptrs).second; \ 1752 !SYNCHRONIZED_VAR(state); \ 1753 SYNCHRONIZED_VAR(state) = true)
ConstLockedPtr lock(const std::chrono::duration< Rep, Period > &timeout) const
UpgradeLockedPtr ulock(const std::chrono::duration< Rep, Period > &timeout)
UnlockerData releaseLock()
LockedPtrBase(LockedPtrBase< SynchronizedType, Mutex, LockPolicyType > &&rhs) noexcept
ConstLockedPtr contextualRLock(const std::chrono::duration< Rep, Period > &timeout) const
Synchronized(Synchronized &&rhs) noexcept(nxMoveCtor)
LockedPtrBase(LockedPtrBase &&rhs) noexcept
ConstLockedPtr rlock() const
LockedPtrBase(LockedPtrBase &&rhs) noexcept
typename Base::ConstLockedPtr ConstLockedPtr
LockedPtr(SynchronizedType *parent)
void lock(LockableOne &one, LockableTwo &two, Lockables &...lockables)
auto withLockPtr(Function &&function) const
SynchronizedType * getSynchronized() const
auto wlock(Synchronized< D, M > &synchronized, Args &&...args)
auto withWLockPtr(Function &&function)
static std::unique_ptr< SSLLock[]> & locks()
Synchronized(const Synchronized &rhs, const ConstLockedPtr &) noexcept(nxCopyCtor)
typename Base::UnlockerData UnlockerData
typename invoke_result< F, Args... >::type invoke_result_t
ConstLockedPtr lock() const
auto wlock(Synchronized &synchronized, Args &&...args)
LockedPtrBase & operator=(LockedPtrBase< SynchronizedType, Mutex, LockPolicyType > &&rhs) noexcept
auto withRLock(Function &&function) const
ScopedUnlocker(LockedPtr< SynchronizedType, LockPolicy > *p)
LockedPtrBase(SynchronizedType *parent)
void reacquireLock(UnlockerData &&data)
SynchronizedType * UnlockerData
Synchronized(T &&rhs) noexcept(nxMoveCtor)
SynchronizedType::MutexType MutexType
TryUpgradeLockedPtr tryULock()
void swap(Synchronized &rhs)
constexpr auto loop_continue
LockedPtr(LockedPtr< SynchronizedType, LockPolicyType > &&other) noexcept
void assignImpl(LockedPtrBase< SynchronizedType, std::mutex, LockPolicyLhs > &lhs, LockedPtrBase< SynchronizedType, std::mutex, LockPolicyRhs > &rhs) noexcept
ConstLockedPtr operator->() const
ConstLockedPtr contextualLock() const
LockedPtrBase & operator=(LockedPtrBase &&rhs) noexcept
LockedPtr wlock(const std::chrono::duration< Rep, Period > &timeout)
LockedPtr lock(const std::chrono::duration< Rep, Period > &timeout)
constexpr detail::Map< Move > move
LockedPtr< SynchronizedType, LockPolicyFromUpgradeToExclusive > moveFromUpgradeToWrite()
LockedPtr contextualLock()
LockedPtr< SynchronizedType, LockPolicyFromExclusiveToUpgrade > moveFromWriteToUpgrade()
typename std::conditional< std::is_const< SynchronizedType >::value, typename SynchronizedType::DataType const, typename SynchronizedType::DataType >::type SynchronizedDataType
UnlockerData releaseLock()
typename std::remove_const< SynchronizedType >::type Synchronized
CDataType * operator->() const
auto withWLock(Function &&function)
auto rlock(Synchronized &synchronized, Args &&...args)
ConstLockedPtr contextualRLock() const
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
LockedPtrBase(LockedPtrBase< SynchronizedType, std::mutex, LockPolicyType > &&other) noexcept
std::unique_lock< std::mutex > & getUniqueLock()
requires E e noexcept(noexcept(s.error(std::move(e))))
in_place_tag(&)(in_place_tag) in_place_t
ConstTryLockedPtr tryLock() const
Synchronized(std::piecewise_construct_t, std::tuple< DatumArgs... > datumArgs, std::tuple< MutexArgs... > mutexArgs)
FOLLY_PUSH_WARNING RHS rhs
auto makeSynchronizedLocker(Synchronized &synchronized, LockFunc &&lockFunc, TryLockFunc &&tryLockFunc, Args &&...args)
auto rlock(const Synchronized< Data, Mutex > &synchronized, Args &&...args)
std::unique_lock< std::mutex > lock_
std::tuple< detail::LockedPtrType< Sync1 >, detail::LockedPtrType< Sync2 > > acquireLocked(Sync1 &l1, Sync2 &l2)
auto withLock(Function &&function)
typename Base::LockedPtr LockedPtr
constexpr std::decay< T >::type copy(T &&value) noexcept(noexcept(typename std::decay< T >::type(std::forward< T >(value))))
void assignImpl(LockedPtrBase< SynchronizedType, Mutex, LockPolicyLhs > &lhs, LockedPtrBase< SynchronizedType, Mutex, LockPolicyRhs > &rhs) noexcept
Synchronized(const T &rhs) noexcept(nxCopyCtor)
std::pair< detail::LockedPtrType< Sync1 >, detail::LockedPtrType< Sync2 > > acquireLockedPair(Sync1 &l1, Sync2 &l2)
Synchronized(typename std::conditional< std::is_copy_constructible< T >::value, const Synchronized &, NonImplementedType >::type rhs)
LockedPtrBase(SynchronizedType *parent)
ScopedUnlocker< SynchronizedType, LockPolicy > scopedUnlock()
LockedPtr< SynchronizedType, LockPolicyFromUpgradeToShared > moveFromUpgradeToRead()
auto withRLockPtr(Function &&function) const
auto lock(SynchronizedLocker...lockersIn) -> std::tuple< typename SynchronizedLocker::LockedPtr... >
ConstLockedPtr timedAcquire(unsigned int milliseconds) const
Synchronized & operator=(const T &rhs)
std::enable_if_t< std::is_same< typename LockPolicy::UnlockPolicy, typename LockPolicyOther::UnlockPolicy >::value > EnableIfSameUnlockPolicy
LockedPtr contextualLock(const std::chrono::duration< Rep, Period > &timeout)
constexpr auto data(C &c) -> decltype(c.data())
decltype(auto) synchronized(Func &&func, SynchronizedLockers &&...lockers)
typename std::conditional< std::is_const< SynchronizedType >::value, typename SynchronizedType::ConstLockedPtr, typename SynchronizedType::LockedPtr >::type LockedPtrType
GuardImpl guard(ErrorHandler &&handler)
void reacquireLock(UnlockerData &&data)
Synchronized(Synchronized &&rhs, const LockedPtr &) noexcept(nxMoveCtor)
make_integer_sequence< std::size_t, Size > make_index_sequence
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
auto ulock(Synchronized &synchronized, Args &&...args)
Synchronized & operator=(T &&rhs)
LockedPtr & operator=(LockedPtr< SynchronizedType, LockPolicyType > &&other) noexcept
AtomicCounter< T, DeterministicAtomic > Base
LockedPtrBase & operator=(LockedPtrBase< SynchronizedType, std::mutex, LockPolicyType > &&rhs) noexcept
static SynchronizedType * getSynchronized(const UnlockerData &data)
LockedPtr(SynchronizedType *parent, const std::chrono::duration< Rep, Period > &timeout)
Synchronized(std::piecewise_construct_t, std::tuple< DatumArgs... > datumArgs, std::tuple< MutexArgs... > mutexArgs, index_sequence< IndicesOne... >, index_sequence< IndicesTwo... >)
static const char *const value
ConstLockedPtr rlock(const std::chrono::duration< Rep, Period > &timeout) const
invoke_result_t< LockFunc &, Synchronized &, const Args &... > LockedPtr
auto withLock(Function &&function) const
Synchronized & operator=(Synchronized &&rhs)
LockedPtr timedAcquire(unsigned int milliseconds)
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
LockedPtrBase(SynchronizedType *parent, const std::chrono::duration< Rep, Period > &timeout)
CDataType & operator*() const
std::vector< detail::folly::detail::TypeDescriptor > DataType
typename SynchronizedType::DataType DataType
void swap(exception_wrapper &a, exception_wrapper &b) noexcept
SynchronizedLocker(Synchronized &sync, LockFuncType &&lockFunc, TryLockFuncType tryLockFunc, As &&...as)
T exchange(T &obj, U &&new_value)
auto withLockPtr(Function &&function)
static SynchronizedType * getSynchronized(UnlockerData data)
detail::SynchronizedDataType< SynchronizedType > CDataType
Synchronized & operator=(typename std::conditional< std::is_copy_constructible< T >::value &&std::is_move_assignable< T >::value, const Synchronized &, NonImplementedType >::type rhs)
LockedPtr< SynchronizedType, LockPolicyFromExclusiveToShared > moveFromWriteToRead()
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
auto ulock(Synchronized< D, M > &synchronized, Args &&...args)
ScopedUnlocker(ScopedUnlocker &&other) noexcept
auto withULock(Function &&function)
std::tuple< Args... > args_
void swap(Synchronized< T, M > &lhs, Synchronized< T, M > &rhs)
decltype(auto) FOLLY_CPP14_CONSTEXPR fetch(Sequence &&sequence, Index &&index)
ConstLockedPtr contextualLock(const std::chrono::duration< Rep, Period > &timeout) const
decltype(auto) constexpr apply(F &&func, Tuple &&tuple)
Synchronized(in_place_t, Args &&...args)
constexpr auto loop_break
FOLLY_CPP14_CONSTEXPR Func for_each(Sequence &&sequence, Func func)
LockedPtrBase & operator=(LockedPtrBase &&rhs) noexcept
std::pair< std::unique_lock< std::mutex >, SynchronizedType * > UnlockerData
void copy(T *target) const
folly::Function< void()> parent
typename SynchronizedType::MutexType MutexType
auto withULockPtr(Function &&function)
TryRLockedPtr tryRLock() const