目前我们正在大量使用异步值。假设我有一个执行以下操作的函数:
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;
}
在代码中的某个时刻,我们创建了一个任务,它为这样的 int 值创建了一个未来,该值将由 packaged_task 设置 - 像这样(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未来能够等待它或捕获异常)。所以这是本例中的转换函数:
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 超出了范围。
所以我的问题是:我该如何处理这种情况。如何防止任务被破坏?有这种模式吗?
最好的,
罗尼