raf*_*lak 14 c++ multithreading initialization class c++11
我想使用一个管理线程(或几个线程)的类.使用组合,这看起来像:
class MyClass{
private:
std::thread mythread;
void _ThreadMain();
public:
MyClass();
// other fields
}
Run Code Online (Sandbox Code Playgroud)
因为a的默认构造函数std::thread是没有意义的,我需要在MyClass构造函数中显式调用它:
MyClass::MyClass() : mythread(&MyClass::_ThreadMain,this) {}
Run Code Online (Sandbox Code Playgroud)
但是,在这种情况下,该_ThreadMain方法很可能在 MyClass构造之前执行,从而导致任何类型的奇怪行为.这显然是不安全的.我怎样才能解决这个问题?
一个明显的解决方案是使用指针std::thread代替,并添加另一个成员函数:
void MyClass::Start(){
// This time mythread is of type std::thread*
mythread = new std::thread(&MyClass::_ThreadMain,this); // One could use std::unique_pointer instead.
}
Run Code Online (Sandbox Code Playgroud)
这将启动该线程.在这种情况下,它将在构造类之后调用,这确实是安全的.
但是,我想知道是否有任何合理的解决方案可以让我不使用指针.感觉它应该是可能的某种方式(嘿,必须有一种方法来在构建一个类时启动一个线程!),但我无法想出任何不会引起麻烦的事情.
我考虑过使用一个条件变量,_ThreadMain等待构造函数完成它的工作,但是在构造类之前我不能使用它,对吧?(如果MyClass是派生类,这也没有用)
Nem*_*emo 10
一般来说,没有比拥有单独Start功能更好的方法了.
假设MyClass是某个未来(未知)类的基类Derived.如果线程在MyClass构造函数运行时(或之前)启动,则它总是有可能调用被覆盖的某个虚函数的"错误"实现Derived.
避免这种情况的唯一方法是让线程等到Derived完全构造完成之后,唯一的方法是在Derived构造函数完成后调用其他函数告诉线程"go"...这意味着你必须有一些单独调用的Go函数.
你可能只需要一个单独调用的Start函数,而放弃等待的复杂性.
[更新]
请注意,对于复杂的类,"两阶段构造"是一些人推荐的习语.启动线程将无缝地适应"初始化"阶段.
您可以将线程与移动语义结合使用:
class MyClass final
{
private:
std::thread mythread;
void _ThreadMain();
public:
MyClass()
: mythread{} // default constructor
{
// move assignment
mythread = std::thread{&MyClass::_ThreadMain, this};
}
};
Run Code Online (Sandbox Code Playgroud)
移动赋值运算符记录在下一页.特别是,它noexcept并没有创建新的线程.