2013-07-04 60 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