unified single-type interface for channels

master
Daniel Kolesa 2017-03-23 02:44:45 +01:00
parent 0e24dcd1c4
commit 45e65d7ec7
3 changed files with 70 additions and 23 deletions

View File

@ -6,7 +6,8 @@
#ifndef OSTD_CHANNEL_HH #ifndef OSTD_CHANNEL_HH
#define OSTD_CHANNEL_HH #define OSTD_CHANNEL_HH
#include <stdio.h> #include <type_traits>
#include <algorithm>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
@ -19,10 +20,8 @@ struct channel_error: std::logic_error {
using std::logic_error::logic_error; using std::logic_error::logic_error;
}; };
template<typename T, typename C = std::condition_variable> template<typename T>
struct channel { struct channel {
using condition_variable_type = C;
/* default ctor works for default C */ /* default ctor works for default C */
channel(): p_state(new impl) {} channel(): p_state(new impl) {}
@ -67,11 +66,68 @@ struct channel {
} }
private: private:
struct cond_iface {
cond_iface() {}
virtual ~cond_iface() {}
virtual void notify_one() = 0;
virtual void notify_all() = 0;
virtual void wait(std::unique_lock<std::mutex> &) = 0;
};
template<typename C>
struct cond_impl: cond_iface {
cond_impl(): p_cond() {}
template<typename F>
cond_impl(F &func): p_cond(func()) {}
void notify_one() {
p_cond.notify_one();
}
void notify_all() {
p_cond.notify_all();
}
void wait(std::unique_lock<std::mutex> &l) {
p_cond.wait(l);
}
private:
C p_cond;
};
struct cond {
cond() {
new (reinterpret_cast<void *>(&p_condbuf))
cond_impl<std::condition_variable>();
}
template<typename F>
cond(F &func) {
new (reinterpret_cast<void *>(&p_condbuf))
cond_impl<std::result_of_t<F()>>(func);
}
~cond() {
reinterpret_cast<cond_iface *>(&p_condbuf)->~cond_iface();
}
void notify_one() {
reinterpret_cast<cond_iface *>(&p_condbuf)->notify_one();
}
void notify_all() {
reinterpret_cast<cond_iface *>(&p_condbuf)->notify_all();
}
void wait(std::unique_lock<std::mutex> &l) {
reinterpret_cast<cond_iface *>(&p_condbuf)->wait(l);
}
private:
std::aligned_storage_t<std::max(
6 * sizeof(void *), sizeof(cond_impl<std::condition_variable>)
), alignof(std::condition_variable)> p_condbuf;
};
struct impl { struct impl {
impl() {} impl() {
}
template<typename F> template<typename F>
impl(F &func): p_lock(), p_cond(func()) {} impl(F &func): p_lock(), p_cond(func) {}
template<typename U> template<typename U>
void put(U &&val) { void put(U &&val) {
@ -118,7 +174,7 @@ private:
std::list<T> p_messages; std::list<T> p_messages;
mutable std::mutex p_lock; mutable std::mutex p_lock;
C p_cond; cond p_cond;
bool p_closed = false; bool p_closed = false;
}; };

View File

@ -19,9 +19,6 @@
namespace ostd { namespace ostd {
struct thread_scheduler { struct thread_scheduler {
template<typename T>
using channel_type = channel<T>;
~thread_scheduler() { ~thread_scheduler() {
join_all(); join_all();
} }
@ -174,9 +171,6 @@ private:
}; };
public: public:
template<typename T>
using channel_type = channel<T, coro_cond>;
basic_simple_coroutine_scheduler( basic_simple_coroutine_scheduler(
size_t ss = TR::default_size(), size_t ss = TR::default_size(),
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
@ -228,8 +222,8 @@ public:
} }
template<typename T> template<typename T>
channel<T, coro_cond> make_channel() { channel<T> make_channel() {
return channel<T, coro_cond>{[this]() { return channel<T>{[this]() {
return coro_cond{*this}; return coro_cond{*this};
}}; }};
} }
@ -354,9 +348,6 @@ private:
}; };
public: public:
template<typename T>
using channel_type = channel<T, task_cond>;
basic_coroutine_scheduler( basic_coroutine_scheduler(
size_t ss = TR::default_size(), size_t ss = TR::default_size(),
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
@ -409,8 +400,8 @@ public:
} }
template<typename T> template<typename T>
channel<T, task_cond> make_channel() { channel<T> make_channel() {
return channel<T, task_cond>{[this]() { return channel<T>{[this]() {
return task_cond{*this}; return task_cond{*this};
}}; }};
} }
@ -551,7 +542,7 @@ inline void yield(S &sched) {
} }
template<typename T, typename S> template<typename T, typename S>
inline auto make_channel(S &sched) -> typename S::template channel_type<T> { inline channel<T> make_channel(S &sched) {
return sched.template make_channel<T>(); return sched.template make_channel<T>();
} }

View File

@ -60,7 +60,7 @@ namespace detail {
template<typename F> template<typename F>
tpool_func(F &&func) { tpool_func(F &&func) {
if (sizeof(F) <= sizeof(p_buf)) { if (sizeof(tpool_func_impl<F>) <= sizeof(p_buf)) {
p_func = ::new(reinterpret_cast<void *>(&p_buf)) p_func = ::new(reinterpret_cast<void *>(&p_buf))
tpool_func_impl<F>{std::move(func)}; tpool_func_impl<F>{std::move(func)};
} else { } else {
@ -81,7 +81,7 @@ namespace detail {
} }
private: private:
std::aligned_storage_t< std::aligned_storage_t<
sizeof(std::packaged_task<void()>) + sizeof(void *) sizeof(tpool_func_impl<std::packaged_task<void()>>)
> p_buf; > p_buf;
tpool_func_base *p_func; tpool_func_base *p_func;
}; };