2015-06-23 35 views
5

关于std::thread有一点我不明白: 为什么std::thread的构造函数需要函数运行rvalue?为什么std :: thread函数是由右值运行的?

我通常想与一些成员运行Functor到另一个线程。像这样:

struct Function 
{ 
    void operator() (/* some args */) 
    { 
     /* some code */ 
    } 

    /* some members */ 
} 


void run_thread() 
{ 
    Functor f(/* some data */); 
    std::thread thread(f, /* some data */); 

    /* do something and wait for thread to finish */ 
} 

当前实现std::thread我必须确定我的对象是实现移动语义。我不明白为什么我不能通过引用来通过它。

额外的问题是:什么意思是通过右值引用函数? Lambda表达式?

+4

'std :: thread'的构造函数通过转发引用来实现其功能。 –

+0

你的对象不需要实现移动语义。如果移动不被支持,它只需要复制。 – nwp

+0

@nwp:什么情况下,什么时候该对象已经删除了复制构造函数?为什么需要该副本? –

回答

6

在你的run_thread方法中,f是一个自动变量。这意味着f范围的底部将被销毁。你声称你将“等待线程完成”,但编译器/运行时系统不知道!它必须假定f将被删除,可能在应该调用其方法的线程有机会开始之前。

通过复制(或移动)f,运行时系统获得对其副本f的生命周期的控制权,并且可以避免一些非常令人讨厌且难以调试的问题。

3

std::reference_wrapper将公开operator()到包装的对象。如果您愿意进行手动终身维护,std::thread t(std::ref(f));将通过引用运行f

当然,在您的代码中,这会导致未定义的行为,因为您没有正确管理生命周期。


最后,请注意生thread是一个糟糕的“客户端代码”工具。 async是一个更好的触摸,但是真的需要一个带有packaged_task s和future s和条件变量的任务队列。 C++ 11增加了足够的线程支持来编写体面的线程系统,但它提供了原语,而不是“客户端代码”工具。

在玩具程序中,它可能已经足够。

相关问题