Skip to content

Instantly share code, notes, and snippets.

@daniel-j-h
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daniel-j-h/a3c3cf172b00f186b85b to your computer and use it in GitHub Desktop.
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)
#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
#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
#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
#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