正确使用boost :: wait_for_any

时间:2014-10-30 02:11:44

标签: c++ multithreading boost boost-asio future

我有一个简单的任务调度程序:调用执行方法,packaged_task返回指向我Task的指针。当一个任务完成后我就会#1;喜欢显示调试数据(涉及到GUI,所以我需要在主线程中执行此操作)。我希望像boost::wait_for_any一样使用j->get(),但boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::promise_already_satisfied> >有时会抛出异常get。这留下了两个想法。要么是因为复制而是异常类所指出的,但是我不知道这发生了什么,或者由于wait_for_any已经被调用,这是不可能发生的,因为期货只能在这个方法块我已经将它们转换为shared_futrues所以它应该可以工作。

那么在Task部分中,我如何找回指向已完成的future实例的指针?

使用shared_future而不是execute编辑

事实证明,我的一个任务的get函数抛出了异常,而期货会将这些异常带到std::vector<boost::future<Task*>> futures; std::vector<Task*> tasks = get_tasks(); for (Task* t : tasks) { typedef boost::packaged_task<Task*()> task_t; task_t task([t]() -> Task* { t->execute(); return t; }); auto fut = task.get_future(); futures.push_back(std::move(fut)); impl->io_service.post(boost::bind(&task_t::operator(), boost::make_shared<task_t>(std::move(task)))); } for (Task* t : tasks) { auto j = boost::wait_for_any(futures.begin(), futures.end()); Task* task = j->get(); task->display_debug(); futures.erase(j); } 调用。代码本身很好(除了缺少的异常处理程序)。但是,使用Boost信号(见下面的答案)可能是更好的方法。

{{1}}

1 个答案:

答案 0 :(得分:2)

嗯。我实际上在这里失去了一点。看起来你做的事情比要求的要复杂得多(为什么你不使用Boost Signals2而不是&#34;轮询&#34;对于特定的&#34;事件&#34;通过期货?看来你是无论如何不要以任何特定的顺序期待它们?)。

对于它的价值,这里有一个适用于我的固定版本。如果我以后有更多时间,我可以比较一下注释,看看解释差异的原因。

查看 Live On Coliru

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread/future.hpp>
#include <iostream>
#include <string>
#include <set>

struct Task
{
    virtual ~Task() = default;
    virtual void execute() {}
    virtual void display_debug() { std::cout << __FUNCTION__ << static_cast<void*>(this) << "\n"; }
};

std::set<Task*> get_tasks()
{
    static std::set<Task*> data{ new Task, new Task };

    return data;
}

int main() {
    struct { boost::asio::io_service io_service; } impl_instance;
    auto impl = &impl_instance;

    std::vector<boost::shared_future<Task*>> futures;
    std::set<Task*> tasks = get_tasks();

    for (Task* t : tasks) {
        typedef boost::packaged_task<Task*> task_t;
        task_t wrap([t]() -> Task* {
            t->execute();
            return t;
        });

        auto fut = wrap.get_future();
        futures.push_back(std::move(fut));

        impl->io_service.post(boost::bind(&task_t::operator(), boost::make_shared<task_t>(std::move(wrap))));
    }

    boost::thread th([&]{ impl->io_service.run(); });

    while (!futures.empty()) {
        auto j = boost::wait_for_any(futures.begin(), futures.end());
        auto fut = *j;
        futures.erase(j);

        Task* task = fut.get();
        task->display_debug();

        // optionally:
        // tasks.erase(task);
    }

    th.join();
}