2013-07-04 57 views
1

我很好奇,爲什麼會崩潰在大約1個運行在4異步參考拉姆達崩潰

我有一個簡單的類,返回一個線程ID的字符串。 該類在lambda中異步調用另一個類並返回結果。代碼很簡單,只要我能做到 - 我仍然在學習:

class String_Returner 
{ 
public: 
    string run() const 
    { 
     return "I returned from thread "+to_string(this_thread::get_id()); 
    } 
}; 

class Class_Holder 
{ 
public: 
    Class_Holder() : number_of_runs(10) 
    { 
     srs.resize(number_of_runs); 
    } 

    void concurrent_srs() 
    { 
     for (int i = 0; i < number_of_runs; i++) 
     { 
      results.push_back(async([&]{return srs[i].run();})); 
     } 

     for (int i = 0; i < results.size(); i++) 
     { 
      cout << i << ") " << results[i].get() << endl; 
     } 

     results.clear(); 
    } 
private: 
    vector<future<string>> results; 
    vector<String_Returner> srs; 
    const int number_of_runs; 
}; 

void class_b_test() 
{ 
    Class_Holder ch; 
    ch.concurrent_srs(); 
} 

我意識到使用異步與參考是危險的,但我想它會是安全的,如果沒有被寫入。我想我的錯誤可能來自lambda本身。這主要是一個測試異步和lambdas功能的程序。

所以我的主要問題: 1)爲什麼它崩潰? 2)有什麼更好的方法來做到這一點?

回答

3

爲什麼會崩潰?

results.push_back(async([&]{return srs[i].run();})); 

沒有什麼錯,在該行的參考srs;正如你所說,它沒有被修改。但是提及i是完全沒有意義的;當lambda執行時,i可能不再存在,並且其值將不可預知。

但我不明白你爲什麼覺得需要有多個StringReturner。這個類沒有狀態,對於它所做的所有區別,方法也可能是靜態的。

有什麼更好的方法來做到這一點?

究竟做什麼?

+0

該程序的要點是測試lambas和併發性。我不存在很可能是這裏的關鍵。如果我通過我作爲副本,而不是一個參考,應該工作,對嗎?我想我會去試試:) – David

+0

@David:你可以將'i'作爲副本,或者你只是總是使用相同的lambda。我沒有看到有兩個lambda引用兩個不同的無狀態類實例來測試任何東西。如果你想看到不同的StringReturner對象被引用,你必須在對象中放入一些狀態,以便lambdas可見地引用不同的對象。 – rici

+0

我還在學習lambda,這就是整個問題的來源。基本上我知道這些東西是作爲參考傳遞的,但是甚至沒有想到'我'。我今天對這個主題做了一些解讀。我會接受這個答案,因爲它最接近我所要求的。 – David

1

如果你打算無論如何要使用lambda,爲什麼不使用一個直接你想要做什麼:

#include <string> 
#include <iostream> 
#include <thread> 
#include <future> 
#include <sstream> 
#include <vector> 

int main() { 
    std::vector<std::future<std::string>> rets; 

    auto f = []() { 
     std::ostringstream b; 
     b << "returned from: " << std::this_thread::get_id(); 
     return b.str(); 
    }; 

    for (int i=0; i<10; i++) 
     rets.emplace_back(std::async(f)); 

    for (auto & t : rets) { 
     t.wait(); 
     std::cout << t.get() << "\n"; 
    } 
} 

注意,thread::id類型get_id收益是保證有一個operator<<,但至少據我所知,不能保證這是一種std::to_string已被超載的類型。

+0

這看起來很有趣。謝謝回覆。 – David