Last active
August 29, 2015 14:02
-
-
Save daniel-j-h/a3c3cf172b00f186b85b to your computer and use it in GitHub Desktop.
blocking queue, non-blocking queue (Sean Parent's list splice trick), monitor<T>, concurrent<T> (Herb Sutter's primitives)
This file contains 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
#ifndef BLOCKING_QUEUE_H | |
#define BLOCKING_QUEUE_H | |
#include <list> | |
#include <mutex> | |
#include <condition_variable> | |
#include <iterator> | |
template <typename T> | |
class blocking_queue { | |
public: | |
using queue_type = std::list<T>; | |
void enqueue(T x) | |
{ | |
queue_type tmp; | |
tmp.push_back(std::move(x)); | |
{ | |
std::lock_guard<std::mutex> lock(mutex_); | |
q_.splice(std::end(q_), tmp); | |
cv_.notify_one(); | |
} | |
} | |
T dequeue() | |
{ | |
queue_type result; | |
{ | |
std::unique_lock<std::mutex> lock(mutex_); | |
cv_.wait(lock, [&] { return !q_.empty(); }); | |
result.splice(std::end(result), q_, std::begin(q_)); | |
} | |
return result.front(); | |
} | |
private: | |
std::mutex mutex_; | |
std::condition_variable cv_; | |
queue_type q_; | |
}; | |
#endif |
This file contains 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
#ifndef CONCURRENT_H | |
#define CONCURRENT_H | |
#include <functional> | |
#include <future> | |
#include <memory> | |
#include <thread> | |
#include <mutex> | |
#include <exception> | |
#include "blocking_queue.h" | |
namespace { | |
template <typename Fut, typename F, typename T> | |
void set_value(std::promise<Fut>& p, F& f, T& t) | |
{ | |
p.set_value(f(t)); | |
} | |
template <typename F, typename T> | |
void set_value(std::promise<void>& p, F& f, T& t) | |
{ | |
f(t); | |
p.set_value(); | |
} | |
} | |
template <typename T> | |
class concurrent { | |
private: | |
mutable T t; | |
mutable blocking_queue<std::function<void()>> q; | |
bool done = false; | |
std::thread thd; | |
public: | |
concurrent(T t_ = T{}) | |
: t(t_), | |
thd{[=] { | |
while (!done) | |
q.dequeue()(); | |
}} | |
{ | |
} | |
~concurrent() | |
{ | |
q.enqueue([=] { done = true; }); | |
thd.join(); | |
} | |
template <typename F> | |
auto operator()(F f) const -> std::future<decltype(f(t))> | |
{ | |
auto p = std::make_shared<std::promise<decltype(f(t))>>(); | |
auto ret = p->get_future(); | |
q.enqueue([=] { | |
try | |
{ | |
set_value(*p, f, t); | |
} | |
catch (...) | |
{ | |
p->set_exception(std::current_exception()); | |
} | |
}); | |
return ret; | |
} | |
}; | |
#endif |
This file contains 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
#ifndef MONITOR_H | |
#define MONITOR_H | |
#include <mutex> | |
template <typename T> | |
class monitor { | |
private: | |
mutable T t; | |
mutable std::mutex m; | |
public: | |
monitor(T t_ = T{}) : t(t_) | |
{ | |
} | |
template <typename F> | |
auto operator()(F f) const -> decltype(f(t)) | |
{ | |
std::lock_guard<std::mutex> _{m}; | |
return f(t); | |
} | |
}; | |
#endif |
This file contains 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
#ifndef NONBLOCKING_QUEUE_H | |
#define NONBLOCKING_QUEUE_H | |
#include <mutex> | |
#include <list> | |
#include <iterator> | |
template <typename T> | |
class nonblocking_queue { | |
public: | |
using queue_type = std::list<T>; | |
bool enqueue(T x) | |
{ | |
bool was_dry; | |
queue_type tmp; | |
tmp.push_back(std::move(x)); | |
{ | |
std::lock_guard<std::mutex> lock(mutex_); | |
was_dry = was_dry_; | |
was_dry_ = false; | |
q_.splice(std::end(q_), tmp); | |
} | |
return was_dry; | |
} | |
queue_type dequeue() | |
{ | |
queue_type result; | |
{ | |
std::lock_guard<std::mutex> lock(mutex_); | |
if (q_.empty()) | |
was_dry_ = true; | |
else | |
result.splice(std::end(result), q_, std::begin(q_)); | |
} | |
return result; | |
} | |
private: | |
std::mutex mutex_; | |
queue_type q_; | |
bool was_dry_ = true; | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment