現在、非同期値を非常に頻繁に使用しています。次のような関数があるとします。
int do_something(const boost::posix_time::time_duration& sleep_time)
{
BOOST_MESSAGE("Sleeping a bit");
boost::this_thread::sleep(sleep_time);
BOOST_MESSAGE("Finished taking a nap");
return 42;
}
コードのある時点で、packaged_task によって設定される int 値への未来を作成するタスクを作成します (この例では、worker_queue は boost::asio::io_service です)。
boost::unique_future<int> createAsynchronousValue(const boost::posix_time::seconds& sleep)
{
boost::shared_ptr< boost::packaged_task<int> > task(
new boost::packaged_task<int>(boost::bind(do_something, sleep)));
boost::unique_future<int> ret = task->get_future();
// Trigger execution
working_queue.post(boost::bind(&boost::packaged_task<int>::operator (), task));
return boost::move(ret);
}
コードの別の時点で、この関数をラップして、未来でもある高レベルのオブジェクトを返したいと考えています。最初の値を取り、それを別の値に変換する変換関数が必要です (実際のコードでは、応答に先物を返すいくつかの階層化と非同期 RPC を実行しています。これらの応答は、実際のオブジェクト、POD、または void への先物に変換する必要があります。 future を待機したり、例外をキャッチしたりできます)。したがって、これはこの例の変換関数です。
float converter(boost::shared_future<int> value)
{
BOOST_MESSAGE("Converting value " << value.get());
return 1.0f * value.get();
}
次に、必要な場合にのみこの変換を行うために、Boost ドキュメントで説明されているように遅延未来を作成することを考えました。
void invoke_lazy_task(boost::packaged_task<float>& task)
{
try
{
task();
}
catch(boost::task_already_started&)
{}
}
そして、ラップされた未来を作成する関数 (より高いレベルの API である可能性があります) があります。
boost::unique_future<float> createWrappedFuture(const boost::posix_time::seconds& sleep)
{
boost::shared_future<int> int_future(createAsynchronousValue(sleep));
BOOST_MESSAGE("Creating converter task");
boost::packaged_task<float> wrapper(boost::bind(converter, int_future));
BOOST_MESSAGE("Setting wait callback");
wrapper.set_wait_callback(invoke_lazy_task);
BOOST_MESSAGE("Creating future to converter task");
boost::unique_future<float> future = wrapper.get_future();
BOOST_MESSAGE("Returning the future");
return boost::move(future);
}
最後に、次のように使用できるようにしたいと思います。
{
boost::unique_future<float> future = createWrappedFuture(boost::posix_time::seconds(1));
BOOST_MESSAGE("Waiting for the future");
future.wait();
BOOST_CHECK_EQUAL(future.get(), 42.0f);
}
しかし、ここでは、約束が破られたという例外が発生します。変換を行う packaged_task が範囲外になるため、その理由は私にとってはかなり明確なようです。
だから私の探求は次のとおりです。そのような状況にどのように対処しますか。タスクが破棄されないようにするにはどうすればよいですか? これにはパターンがありますか?
ベスト、
ロニー