Created
September 16, 2015 16:43
-
-
Save 3noch/5848cb2ccf4850772c51 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <boost/thread.hpp> | |
#include <CeBaseTypes.h> | |
#include <Maybe.h> | |
/** | |
* A concurrency primitive which may contain a single value or be empty. | |
* | |
* An exclusive box can be empty or full: | |
* * "Putting" fills the box with a value. | |
* * "Taking" empties the box and returns it to the caller. | |
* * "Reading" returns a copy to the caller without emptying the box. | |
* * When full, "putters" will block until it's empty. | |
* * When empty, both "takers" and "readers" will block until it's full. | |
* | |
* If you need scoped, atomic access to data, use ce::Atomic instead. | |
* | |
* Modeled directly after Haskell's MVar (mutable variable): | |
* https://hackage.haskell.org/package/base/docs/Control-Concurrent-MVar.html | |
* Implementation based on: | |
* https://gist.github.com/qzchenwl/ec43b275f8ad27c5b629#file-mvar-hpp | |
* (mirrored at https://gist.github.com/3noch/a583e43ead2a8b008ddd#file-mvar-hpp) | |
*/ | |
template<typename T> | |
struct ExclusiveBox final : private Noncopyable | |
{ | |
ExclusiveBox() {} | |
ExclusiveBox(T t) | |
: slot_(std::move(t)) {} | |
/** | |
* Fills the slot, blocking until it's empty if necessary. | |
*/ | |
void put(T t) | |
{ | |
boost::unique_lock<boost::shared_mutex> lock(mtx_); | |
while (slot_.full()) { putCond_.wait(lock); } | |
slot_ = std::move(t); | |
readCond_.notify_all(); | |
takeCond_.notify_one(); | |
} | |
/** | |
* Empties and returns the contents of the slot, blocking until it's full if necessary. | |
*/ | |
T take() | |
{ | |
boost::unique_lock<boost::shared_mutex> lock(mtx_); | |
while (!slot_.full()) { takeCond_.wait(lock); } | |
T x = std::move(*slot_); | |
slot_ = Nothing(); | |
putCond_.notify_one(); | |
return std::move(x); | |
} | |
/** | |
* Returns a copy of the contents of the slot, blocking until it's full if necessary. | |
*/ | |
T read() const | |
{ | |
boost::shared_lock<boost::shared_mutex> lock(mtx_); | |
while (!slot_.full()) { readCond_.wait(lock); } | |
return *slot_; | |
} | |
private: | |
mutable boost::shared_mutex mtx_; | |
boost::condition_variable_any putCond_; | |
boost::condition_variable_any takeCond_; | |
mutable boost::condition_variable_any readCond_; | |
Maybe<T> slot_; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment