【发布时间】:2018-10-26 00:48:58
【问题描述】:
在下面的代码中,考虑到我的线程函数通过右值引用获取参数,我无法理解为什么类的移动构造函数被调用两次,所以我希望当参数被移动到线程构造函数时,移动构造函数只会被调用一次。有人可以提供有关线程构造函数如何工作以及它如何将参数传递给线程函数的见解。
#include <iostream>
#include <thread>
#include <chrono>
class Test {
public:
Test() {}
Test(Test&&)
{
std::cout<<"Move Constructor Called..."<<std::endl;
}
};
void my_thread_func(Test&& obj)
{
using namespace std::chrono_literals;
std::cout<<"Inside thread function..."<<std::endl;
std::this_thread::sleep_for(2s);
}
int main() {
std::thread t(my_thread_func,Test());
std::cout << "Hello World!\n";
t.join();
return 0;
}
这个问题不关心线程构造函数参数是按值传递的,而是更关心为什么移动构造函数被调用两次?
【问题讨论】:
-
您是否逐步调试过?在
std::cout<<"Move Constructor Called..."<<std::endl;处设置一个断点,当执行在那里停止时,查看调用堆栈(从那里调用了Test::Test())。我怀疑一个电话是std::thread::thread(),另一个电话是my_thread_func()。我很乐意阅读您可以在调试器中观察到的内容。 -
@Scheff 尝试在 onlinegdb.com 上逐步调试,但无法理解调用堆栈,因为似乎一个调用来自线程构造函数,另一个来自线程 impl
-
@Kapil 我在想,如果有一个
std::thread对象按值取Test,我们还可以看到(至少在 gcc 上)有一个std::shared_ptr到_Impl_Base。Test如何在不额外移动的情况下从std::thread传递到_Impl_Base? -
我已经深入研究了 gcc7.3 中 std::thread 的实现。它调用一个函数,该函数创建一个“调用者”结构,该结构本质上包含一个线程函数及其参数的元组,并按值返回它。然后实现在堆上分配另一个“状态”结构,其中包含“调用者”的副本。那是两个构造函数。我认为这是多余的,实现可以直接在堆上创建对象,而无需构造临时调用程序。不过,实现必须变得更复杂一些。
-
我们也有这个问题phrased in terms of copies。
标签: c++ multithreading std stdthread perfect-forwarding