ブーストはfutures and other threading tools implementedです。
boost::unique_future
でget()
メソッドを呼び出すと、非同期実行中にその中に格納されていた可能性のある例外がすべて再スローされることに注意してください。
私はあなたのような何かをすることをお勧め:
#pragma once
#include <tbb/concurrent_queue.h>
#include <boost/thread.hpp>
#include <boost/noncopyable.hpp>
#include <functional>
namespace internal
{
template<typename T>
struct move_on_copy
{
move_on_copy(const move_on_copy<T>& other) : value(std::move(other.value)){}
move_on_copy(T&& value) : value(std::move(value)){}
mutable T value;
};
template<typename T>
move_on_copy<T> make_move_on_copy(T&& value)
{
return move_on_copy<T>(std::move(value));
}
}
class executor : boost::noncopyable
{
boost::thread thread_;
tbb::concurrent_bounded_queue<std::function<void()>> execution_queue_;
template<typename Func>
auto create_task(Func&& func) -> boost::packaged_task<decltype(func())> // noexcept
{
typedef boost::packaged_task<decltype(func())> task_type;
auto task = task_type(std::forward<Func>(func));
task.set_wait_callback(std::function<void(task_type&)>([=](task_type& my_task) // The std::function wrapper is required in order to add ::result_type to functor class.
{
try
{
if(boost::this_thread::get_id() == thread_.get_id()) // Avoids potential deadlock.
my_task();
}
catch(boost::task_already_started&){}
}));
return std::move(task);
}
public:
explicit executor() // noexcept
{
thread_ = boost::thread([this]{run();});
}
~executor() // noexcept
{
execution_queue_.push(nullptr); // Wake the execution thread.
thread_.join();
}
template<typename Func>
auto begin_invoke(Func&& func) -> boost::unique_future<decltype(func())> // noexcept
{
// Create a move on copy adaptor to avoid copying the functor into the queue, tbb::concurrent_queue does not support move semantics.
auto task_adaptor = internal::make_move_on_copy(create_task(func));
auto future = task_adaptor.value.get_future();
execution_queue_.push([=]
{
try{task_adaptor.value();}
catch(boost::task_already_started&){}
});
return std::move(future);
}
template<typename Func>
auto invoke(Func&& func) -> decltype(func()) // noexcept
{
if(boost::this_thread::get_id() == thread_.get_id()) // Avoids potential deadlock.
return func();
return begin_invoke(std::forward<Func>(func), prioriy).get();
}
private:
void run() // noexcept
{
while(true)
{
std::function<void()> func;
execution_queue_.pop(func);
if(!func)
break;
func();
}
}
};
このように、スレッド間で結果を渡す方法について説明しています。スレッドはメモリを共有しているため、それらはすべてあなたのコントロール下にあります。なぜ、これにメタ構造を適用する必要がありますか?単に結果を含む具体的なクラスを作成し、結果が得られたときに通知するのはなぜでしょうか。 – Jay
偉大な質問、ジェイ。先物パラダイムを使用する本当の理由は、非同期タスクから結合スレッドに例外を持ち込むことができるようにすることです。 – Tom