/*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <type_traits>
#include <mutex>
#include <boost/thread.hpp>
-#include "folly/Preprocessor.h"
-#include "folly/Traits.h"
+#include <folly/Preprocessor.h>
+#include <folly/Traits.h>
namespace folly {
struct HasLockUnlock {
enum { value = IsOneOf<T,
std::mutex, std::recursive_mutex,
- boost::mutex, boost::recursive_mutex, boost::shared_mutex,
+ boost::mutex, boost::recursive_mutex, boost::shared_mutex
#ifndef __APPLE__ // OSX doesn't have timed mutexes
- std::timed_mutex, std::recursive_timed_mutex,
+ ,std::timed_mutex, std::recursive_timed_mutex,
boost::timed_mutex, boost::recursive_timed_mutex
#endif
>::value };
IsOneOf<T, std::timed_mutex, std::recursive_timed_mutex>::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)));
}
/**
* constructor.
*/
Synchronized() = default;
- /**
+ /**
* Copy constructor copies the data (with locking the source and
* all) but does NOT copy the mutex. Doing so would result in
* deadlocks.
* 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) : datum_(std::move(rhs)) {}
/**
* The canonical assignment operator only assigns the data, NOT the
* 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_;
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.
*/
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<T> object locked for the duration of lp's
return;
}
// Could not acquire the resource, pointer is null
- parent_ = NULL;
+ parent_ = nullptr;
}
/**
* SYNCHRONIZED below.
*/
T* operator->() {
- return parent_ ? &parent_->datum_ : NULL;
+ return parent_ ? &parent_->datum_ : nullptr;
}
/**
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) {
}
const T* operator->() const {
- return parent_ ? &parent_->datum_ : NULL;
+ return parent_ ? &parent_->datum_ : nullptr;
}
struct Unsynchronizer {
}
auto guard1 = operator->();
auto guard2 = rhs.operator->();
- datum_.swap(rhs.datum_);
+
+ using std::swap;
+ swap(datum_, rhs.datum_);
}
/**
*/
void swap(T& rhs) {
LockedPtr guard = operator->();
- datum_.swap(rhs);
+
+ using std::swap;
+ swap(datum_, rhs);
}
/**