From: Philip Pronin Date: Fri, 5 Jul 2013 03:01:37 +0000 (-0700) Subject: move assignment operators for folly::Synchronized X-Git-Tag: v0.22.0~934 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=ca5621faf0871fa56f16754f03032cd03e03d4b1;hp=b1463f8f7e68895866b62913997423feb338aeb1 move assignment operators for folly::Synchronized Summary: * added move assignment operators, * fixed `operator=(const Synchronized& rhs)` (it had a typo), * fixed deadlock on self-assignment, * changed `swap` to call `swap(lhs.datum_, rhs.datum_)` instead of `lhs.datum_.swap(rhs.datum_)`. Test Plan: fbconfig -r folly/test && fbmake opt -j32 && fbmake runtests_opt Reviewed By: delong.j@fb.com FB internal diff: D875977 --- diff --git a/folly/Synchronized.h b/folly/Synchronized.h index cc43071a..d632a772 100644 --- a/folly/Synchronized.h +++ b/folly/Synchronized.h @@ -190,8 +190,8 @@ struct Synchronized { * 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. @@ -220,7 +220,7 @@ struct Synchronized { * 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 @@ -228,7 +228,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_; @@ -240,6 +242,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. */ @@ -249,6 +271,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 @@ -519,7 +550,9 @@ struct Synchronized { } auto guard1 = operator->(); auto guard2 = rhs.operator->(); - datum_.swap(rhs.datum_); + + using std::swap; + swap(datum_, rhs.datum_); } /** @@ -528,7 +561,9 @@ struct Synchronized { */ void swap(T& rhs) { LockedPtr guard = operator->(); - datum_.swap(rhs); + + using std::swap; + swap(datum_, rhs); } /** diff --git a/folly/docs/Synchronized.md b/folly/docs/Synchronized.md index a7e27680..e36f1dbb 100644 --- a/folly/docs/Synchronized.md +++ b/folly/docs/Synchronized.md @@ -183,6 +183,9 @@ An additional assignment operator accepts a `const T&` on the right-hand side. The operator copies the datum inside a critical section. +In addition to assignment operators, `Synchronized` has move +assignment operators. + An additional `swap` method accepts a `T&` and swaps the data inside a critical section. This is by far the preferred method of changing the guarded datum wholesale because it keeps the lock