关于 std::thread 类的问题

Posted

技术标签:

【中文标题】关于 std::thread 类的问题【英文标题】:Questions about std::thread class 【发布时间】:2019-02-05 17:21:21 【问题描述】:

考虑以下类头:

class ThreadClass 
public:
  ThreadClass();
  ~ThreadClass();
  void operator()(int val);
  void set(int val);
  int get();
private:
  int x;
;

以及以下实现:

ThreadClass::ThreadClass(): x(0) 
  std::cout << "Constructing..." << std::endl;

ThreadClass::~ThreadClass() 
  std::cout << "Destructing..." << std::endl;

void ThreadClass::operator()(int val) 
  set(val);
  std::cout << get() << std::endl;
  set(val * 2);
  std::cout << get() << std::endl;

void ThreadClass::set(int val) 
  x = val;

int ThreadClass::get() 
  return x;

启动以下main,类析构函数被调用多次而不是一次:

int main(int argc, char const *argv[]) 
  std::thread x = std::thread(ThreadClass(), 10);
  x.join();
  return 0;


>>> Constructing...
>>> Destructing...
>>> Destructing...
>>> 10
>>> 20
>>> Destructing...

由于我对std::thread类的了解不是很深,所以想请教一下:

    为什么会这样?真诚地,我期待的只是 ThreadClass 的一个实例。 为了避免意外行为,是否需要重载某些类运算符?

【问题讨论】:

移动和复制构造函数? 【参考方案1】:

您正在调用尚未定义的隐式构造函数(尚未为您创建)。您可以在此处查看它们的实际效果:

#include <thread>
#include <iostream>

class ThreadClass 
public:
  ThreadClass() 
    std::cout << "Constructing..." << std::endl;
  
  
  ThreadClass(const ThreadClass& t) 
    std::cout << "Copy constructing..." << std::endl;
    this->x = t.x;
  
  
//   ThreadClass(ThreadClass&& t) 
//     std::cout << "Move constructing..." << std::endl;
//     this->x = t.x;
//   
  
  ~ThreadClass() 
    std::cout << "Destructing..." << std::endl;
  
  
  void operator()(int val) 
      set(val);
      std::cout << get() << std::endl;
      set(val * 2);
      std::cout << get() << std::endl;
  
  void set(int val) 
      x = val;
  
  int get() 
      return x;
  
private:
  int x;
;

int main(int argc, char const *argv[]) 
  std::thread x = std::thread(ThreadClass(), 10);
  x.join();
  return 0;

输出:

正在构建...

复制构造...

复制构造...

破坏……

破坏……

10

20

破坏……

如果您还想查看移动构造函数的实际效果,可以取消注释。

直接回答您的问题:

为什么会这样?真诚地,我期待的只是 ThreadClass 的一个实例。

发生这种情况是因为您正在传递一个对象,因此帖子中提到的其他构造函数被多次调用。

为了避免意外行为,是否需要重载一些类操作符?

您所说的意外行为是什么意思?这完全按照 C++ 的意图执行。这是 C++ 定义明确的行为。

【讨论】:

由于我对 special members 类仍然不熟悉,我在问自己这个多次调用析构函数是否会造成内存分配问题,但这是一个无意义的自我问题:由于该类实例被复制然后销毁,因此在执行函数对象时实例仍然是一个。

以上是关于关于 std::thread 类的问题的主要内容,如果未能解决你的问题,请参考以下文章

c++11的std::thread能用类的成员函数构造一个线程吗?语法怎样?

关于std::thread以及std::condition_variable的一些细节备忘

OpenCV 分配导致 std::thread::join 中的段错误

带有类参数的 std::thread 初始化导致类对象被多次复制

是否可以定义一个 std::thread 并稍后对其进行初始化?

使用 std::thread 或 CreateThread()? [复制]