2014-10-30 4 views
1

У меня есть простой планировщик задач: вызывается метод execute, а packaged_task возвращает указатель на мой Task. Когда задача завершилась, мне нужно показать данные отладки (графический интерфейс задействован, поэтому мне нужно сделать это в основном потоке). Я бы хотел использовать boost::wait_for_any для этого, как показано, однако j->get() иногда выдает исключение boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::promise_already_satisfied> >. Это оставляет мне две мысли. Либо это из-за копирования, которое указывает класс исключения, но я бы не видел, где это происходит, или из-за того, что он уже вызван get, что не может произойти, поскольку фьючерсы видны только в этом блоке методов, и я уже преобразовал их в shared_futrues поэтому он должен работать.правильное использование boost :: wait_for_any

Так что в части wait_for_any, как бы я вернул указатель на экземпляр 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); 
} 

ответ

1

Mmm. Я резко потерял след здесь. Кажется, вы делаете что-то более сложное, чем требуется (почему бы вам не использовать Boost Signals2 вместо «опроса» для определенных «событий» через фьючерсы? Кажется, вы не ожидаете их в каком-либо конкретном порядке в любом случае?).

Для чего это стоит, вот скопированная версия, которая работает для меня. Если у меня будет больше времени, я могу сравнить заметки, чтобы понять, что объясняет разницу.

Посмотреть 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(); 
} 
+1

В случае, если вы заинтересованы, вот подобная демонстрация с использованием сигналов Повысьте эффективность: ** [Live On Coliru] (http://coliru.stacked-crooked.com/ a/f155fdcc19f25400) ** – sehe

+0

Оказывается, исключение было выбрано в функцию 'execute' одной из моих задач, и фьючерсы будут нести эти исключения до вызова' get'. Сам код был прав (за исключением отсутствующего обработчика исключений). Однако использование сигналов усиления может быть лучше. – Mene

Смежные вопросы