2014-10-30 78 views
1

我有一個簡單的任務調度:一個execute方法被調用,並packaged_task返回一個指向我Task。當任務完成後,我想顯示調試數據(涉及GUI,因此我需要在主線程中執行此操作)。我想爲此使用boost::wait_for_any,但j->get()有時會拋出異常boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::promise_already_satisfied> >。這讓我有兩個想法。無論是由於複製,其異常類指示,但我不會看到這個occures,或由於get被已經調用,這不能發生,因爲期貨是隻在這個方法塊可見的,我已經他們轉化爲shared_futrues所以它應該工作。正確使用升壓:: 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

嗯。我在這裏很難跟蹤一點。看起來你正在做的事情比所需要的要複雜一點(爲什麼你不使用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

如果你有興趣,這裏是使用Boost信號類似的演示:** [住在Coliru(http://coliru.stacked-crooked.com/ a/f155fdcc19f25400)** – sehe 2014-10-30 08:57:04

+0

原來我的任務之一的'execute'函數拋出了異常,期貨將這些異常帶到'get'調用。代碼本身很好(除了缺少的異常處理程序)。然而使用升壓信號可能是更好的方法。 – Mene 2014-10-30 13:33:05