是否可以定义一个 std::thread 并稍后对其进行初始化?
Posted
技术标签:
【中文标题】是否可以定义一个 std::thread 并稍后对其进行初始化?【英文标题】:Is it possible to define an std::thread and initialize it later? 【发布时间】:2013-08-24 22:06:38 【问题描述】:我的目标是保留std::thread
对象作为数据成员,并在需要时对其进行初始化。
我无法执行此操作(如下面的代码所示),因为 std::thread
类的复制构造函数已被删除。还有其他方法吗?
class MyClass
public:
MyClass():DiskJobThread();
~MyClass();
void DoDiskJobThread();
private:
int CopyThread(const std::wstring & Source, const std::wstring & Target);
int MoveThread(const std::wstring & Source, const std::wstring & Target);
std::thread DiskJobThread;
;
MyClass::~MyClass()
DiskJobThread.join();
void MyClass::DoDiskJobThread()
std::wstring Source = GetSource();
std::wstring Target = GetTarget();
int m_OperationType = GetOperationType();
if (m_OperationType == OPERATION_COPY)
DiskJobThread = std::thread(&MyClass::CopyThread, *this, Source, Target);
else if (m_OperationType == OPERATION_MOVE)
DiskJobThread = std::thread(&MyClass::MoveThread, *this, Source, Target);
【问题讨论】:
传递this
而不是取消引用 *this
。
【参考方案1】:
用指针包裹它怎么样?
std::unique_ptr<std::thread> thread_ptr;
// Look into std::make_unique if possible
thread_ptr = std::unique_ptr<std::thread>(new std::thread(...));
编辑: 是的,其他人已经提到它,我觉得没有必要在这里添加它,但为了避免更多的反对意见堆积,我会说:你是通过 *this
而不是 this
从而复制您的类的实例。 (出现问题是因为它是不可复制的。通过this
,你应该很高兴。)
【讨论】:
现在thread_ptr
不再比原来的DiskJobThread
更可复制和移动,不过......
@KerrekSB 是的,但如果目标只是稍后初始化,我认为应该没问题;o
-1:问题不在于初始化std::thread
(因为它使用了一个很好的移动分配操作),所以这不能回答问题。
@Angew 好的,我已将答案更新为至少提及问题的第二部分。
@MohammadAliBaydoun 您的答案的问题是它根本不需要 - 按值存储 std::thread
非常好,它确实可以稍后初始化,就像 OP 正在做的那样。将其存储在 unique_ptr
中只会通过动态分配/解除分配和间接引入效率低下。【参考方案2】:
您的问题是其他问题-您将MyClass
的实例传递给线程,而不是成员函数期望的指向MyClass
的指针。只需像这样更改DoDiskJobThread()
(不要取消引用this
):
void MyClass::DoDiskJobThread()
std::wstring Source = GetSource();
std::wstring Target = GetTarget();
int m_OperationType = GetOperationType();
if (m_OperationType == OPERATION_COPY)
DiskJobThread = std::thread(&MyClass::CopyThread, this, Source, Target);
else if (m_OperationType == OPERATION_MOVE)
DiskJobThread = std::thread(&MyClass::MoveThread, this, Source, Target);
您收到错误是因为*this
导致尝试将MyClass
复制到线程函数中,并且您的类的复制ctor 被删除(因为std::thread
的复制ctor 被删除)。但是,成员函数CopyThread
和MoveThread
无论如何都需要一个指针作为第一个(隐藏)参数。
Live demonstration
【讨论】:
+1,是的,我没有注意到他通过*this
而不是this
,你是对的;|
'=' 运算符不允许将新线程对象分配给 DiskJobThread
变量。我收到此错误:error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::thread' (or there is no acceptable conversion)
@hkBattousai 您发布的代码中没有const std::thread
(您可以在ideone上看到我的更改有效)。发布您的实际代码。
我认为您可以使用稍微更晦涩的方法传递std::ref(*this)
,但这会非常愚蠢。【参考方案3】:
线程对象创建后不能初始化;根据定义,初始化发生在创建对象时。但是你可以使用swap
将一个线程对象移动到另一个对象中:
std::thread thr1; // no thread of execution
std::thread thr2(my_function_object); // creates thread of execution
thr1.swap(thr2); // thr1 is now running the thread created as thr2
// and thr2 has no thread of execution
【讨论】:
它不起作用。抛出此错误:C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(611): error C2280: 'std::thread::thread(const std::thread &)' : 试图引用已删除的函数 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\thread(70) : 请参阅“std::thread::thread”的声明 1> 此诊断发生在生成的编译器中函数'Abc::Abc(const Abc &) @codeLover -- 问题出在你的类Abc
中,它显然有一个 std::thread
作为数据成员。std::thread
不可复制,所以你的类必须禁用复制构造或者有一个复制构造函数,以某种方式尝试复制该线程对象。【参考方案4】:
我的目标是保留
std::thread
对象作为数据成员,并在需要时对其进行初始化。
由于默认构造的std::thread
对象没有关联的执行线程,您可以通过使用这样的对象作为(移动)赋值操作的目标来实现这一点。不过要注意,下面的不是初始化,而是赋值:
std::thread th; // no thread of execution associated with th object
// ...
th = std::thread(func);
使用std::thread(func)
创建的临时std::thread
对象具有关联的执行线程。该执行线程的所有权通过移动分配转移给th
——即th
从临时线程中窃取了该执行线程的所有权。
请注意,如果在分配时th
有一个关联的执行线程,则会调用std::terminate()
。
【讨论】:
以上是关于是否可以定义一个 std::thread 并稍后对其进行初始化?的主要内容,如果未能解决你的问题,请参考以下文章
std::thread 导致应用程序中止并出现错误 R6010
使用多线程加速(std::async、std::thread 还是?)