2015-06-20 67 views
4

我想在不同類型的任務上使用PPL「when_all」。然後給該任務添加一個「然後」調用。PPL when_all與不同類型的任務?

但是,when_all返回帶有向量的任務,所以所有元素必須是相同的類型。那麼,我該如何做到這一點?

這是我想出了,但感覺就像一個黑客攻擊的一位:

//3 different types: 
int out1; 
float out2; 
char out3; 

//Unfortunately I cant use tasks with return values as the types would be different ... 
auto t1 = concurrency::create_task([&out1](){out1 = 1; }); //some expensive operation 
auto t2 = concurrency::create_task([&out2](){out2 = 2; }); //some expensive operation 
auto t3 = concurrency::create_task([&out3](){out3 = 3; }); //some expensive operation 

auto t4 = (t1 && t2 && t3); //when_all doesnt block 

auto t5 = t4.then([&out1, &out2, &out3](){ 
    std::string ret = "out1: " + std::to_string(out1) + ", out2: " + std::to_string(out2) + ", out3: " + std::to_string(out3); 
    return ret; 
}); 
auto str = t5.get(); 

std::cout << str << std::endl; 

任何人有一個更好的主意嗎?

(parallel_invoke塊,所以我不希望使用)

+0

也許是task_group? –

回答

2

工作組將工作。

做不到這一點:

template<class...Ts> 
struct get_many{ 
    std::tuple<task<Ts>...> tasks; 
    template<class T0, size_t...Is> 
    std::tuple<T0,Ts...> 
    operator()(
    std::task<T0> t0, 
    std::index_sequence<Is...> 
){ 
    return std::make_tuple(
     t0.get(), 
     std::get<Is>(tasks).get()... 
    ); 
    } 
    template<class T0> 
    std::tuple<T0,Ts...> 
    operator()(task<T0> t0){ 
    return (*this)(
     std::move(t0), 
     std::index_sequence_for<Ts...>{} 
    ); 
    } 
}; 

template<class T0, class...Ts> 
task<std::tuple<T0,Ts...>> when_every(
    task<T0> next, task<Ts>... later 
){ 
    return next.then(get_many<Ts...>{ 
    std::make_tuple(std::move(later)...) 
    }); 
} 

不與void任務上工作,但在其他任何捆綁組任務的成元組的任務。

獲得void s工作是一個更多的工作。一種方法是編寫get_safe,返回Ttask<T>void_placeholdertask<void>,然後在返回之前過濾結果元組。或者寫一個partition_args,將參數拆分爲task<void>task<T>,並對其中的兩個採取不同的行爲。兩者都有點令人頭疼。我們也可以做一個元組附加模式(我們可以一次處理任務,並且可以將T附加到tuple或對void不做任何事情)。

它使用了兩個C++ 14庫特性(index_sequence和index_sequence_for),但都易於在C++ 11中編寫(每行2-4行),並且實現很容易找到。

我忘記,如果任務是可複製的,我認爲它不在上面的代碼。如果它是可複製的,則上述代碼的較短版本將起作用。任何錯別字的道歉。

+0

謝謝。元組而不是矢量構成了一個不錯的界面。我可能在這裏是錯誤的,但我的印象是,我應該避免打電話get(或等待)。因爲他們阻止並殺死可伸縮性。因此,在屏幕下實現一個自定義的「when_all」來調用「get」似乎對我來說是錯誤的。看看concurrency :: when_all的實現,它看起來像「get」只在所有任務完成後才被調用,所以它不會被阻塞。但是我在這裏深深地陷入了困境。最後,我不確定我如何以非阻塞的方式鏈接和連接任務延續。 –

+0

@someone'get'只在'then'內調用,'then'代碼異步運行(我假設,因爲它返回一個'task'),希望在第一個任務的線程中運行。 – Yakk

+0

酷,我的壞。謝謝。 –