0

現在、非同期値を非常に頻繁に使用しています。次のような関数があるとします。

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 が範囲外になるため、その理由は私にとってはかなり明確なようです。

だから私の探求は次のとおりです。そのような状況にどのように対処しますか。タスクが破棄されないようにするにはどうすればよいですか? これにはパターンがありますか?

ベスト、

ロニー

4

1 に答える 1

0

タスク オブジェクトの有効期間を適切に管理する必要があります。

最も正しい方法はfromboost::packaged_task<float>ではなくreturnです。呼び出し元は、将来のオブジェクトを取得し、将来の値が準備できるまでタスクの有効期間を延長する責任があります。boost::unique_future<float>createWrappedFuture()

または、 で行ったのと同様の方法で、タスク オブジェクトを「保留中」のキュー (グローバルまたはクラス メンバー) に配置することもできますcreateAsynchronousValue。ただし、この場合、タスクの有効期間を明示的に管理し、完了後にキューから削除する必要があります。したがって、このソリューションがタスク オブジェクト自体を返すことに対して利点があるとは思わないでください。

于 2012-10-25T11:34:19.630 に答える