c++ - 如何使用 c++11 std::thread 实现类 QThread 类?

标签 c++ multithreading c++11 qthread

std::thread 不能简单地被类继承,不能在销毁时自动加入等等。

很多陷阱,比如需要使用 std::atomic_bool 来停止,在使用 std::thread 时不能简单地共享对象的 this作为成员变量来执行成员方法。

使用 std::thread 实现类 QThread 有什么好的做法吗?


我的目标是一个可继承的 Thread 类,启用 start()detach()stop() 功能。

例如我写了一个如下:

#include <atomic>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <thread>
#include <vector>

struct Thread {
  Thread(int id) {
    std::atomic_init(&(this->id), id);
    std::atomic_init(&(this->m_stop), false);
  }

  Thread(Thread &&rhs) :
    id(),
    m_stop(),
    m_thread(std::move(rhs.m_thread))
  {
    std::atomic_init(&(this->id), rhs.id.load());
    rhs.id.store(-1);
    std::atomic_init(&(this->m_stop), rhs.m_stop.load());
  }

  virtual ~Thread() {
    this->stop();
  }

  void start() {
    this->m_thread = std::move(std::thread(&Thread::work, this));
  }

  void stop() {
    this->m_stop.store(true);

    if (this->m_thread.joinable()) {
      this->m_thread.join();
    }
  }

  virtual void work() {
    while (!(this->m_stop)) {
      std::chrono::milliseconds ts(5000);
      std::this_thread::sleep_for(ts);
    }
  }

  std::atomic_int id;
  std::atomic_bool m_stop;
  std::thread m_thread;
};


int main() {
  srand(42);

  while (true) {
    std::vector<Thread> v;

    for (int i = 0; i < 10; ++i) {
      auto t = Thread(i);
      v.push_back(std::move(t));
      printf("Start %d\n", i);
      v[i].start();
    }
    printf("Start fin!\n");

    int time_sleep = rand() % 2000 + 1000;
    std::chrono::milliseconds ts(time_sleep);
    std::this_thread::sleep_for(ts);

    for (int i = 0; i < 10; ++i) {
      printf("Stop %d\n", i);
      v[i].stop();
      printf("Pop %d\n", i);
      v.pop_back();
    }
    printf("Stop fin!\n");
  }

  return 0;
}

但我很难把它弄好,就在 Stop 0 之后它陷入僵局,或者有时它发生核心转储。

最佳答案

std::thread 旨在作为实现线程原语的最低构建 block 。因此,它不像 QThread 那样提供丰富的接口(interface),但与标准库中的同步原语一起,它允许您非常轻松地实现更复杂的行为,如 QThread 提供的行为。

你正确地注意到从 std::thread 继承是一个坏主意(没有虚拟析构函数是一个死的赠品)而且我认为拥有多态 Thread 类型并不是最聪明的设计放在首位,但如果需要,您可以轻松地将 std::thread 封装为任何类(多态或非多态)的成员。

加入破坏实际上只是一种政策。将 std::thread 封装为成员的类可以简单地在其析构函数中调用 join,有效地实现销毁时的自连接。并发在这里无关紧要,因为根据定义,对象销毁总是非并发执行的。如果您想在多个(可能同时调用的)执行路径之间共享一个线程的所有权,std::shared_ptr 将为您处理。但即使在这里,析构函数也总是由最后一个放弃其 shared_ptr 的剩余线程非并发执行。

QThread::isInterruptionRequested 之类的东西可以用单个标志实现,访问它当然必须由类同步(使用互斥锁或使用原子标志)。

标准未指定更改线程的优先级,因为并非标准设想的所有平台都允许这样做,但您可以使用 native_handle使用特定于平台的代码自行实现。

等等。所有零件都在那里,您只需根据需要组装它们即可。

关于c++ - 如何使用 c++11 std::thread 实现类 QThread 类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42670837/

相关文章:

c++ - 无法将 id 分配给 OpenGL 中的属性

c++ - 为什么 std::tie 没有标记为 C++14 的 constexpr?

C++字符串解析思路

c++ - 如何从 QT C++ 中的文本文件中逐字符读取?

c# - 使用任务并行库时与对象同步

c# - 当所有并行工作单元必须同时运行时,任务是否是合适的选择?

c# - C# Parallel.ForEach 是否对集合的迭代使用相同的线程

C++:从数组中设置多个变量

C++ 将 2d 数组(由 uniqe_ptr 引用)合并到 3d 数组中

c++ - "explicit"构造函数对重载决议的影响