如何使用c ++ 11 std :: thread来实现类似QThread的类?

时间:2017-03-08 12:02:22

标签: c++ multithreading c++11 qthread

std::thread不仅可以通过类继承,也不能在销毁时自动加入等。

当使用std::atomic_bool作为成员变量执行成员方法时,需要使用this进行停止等许多陷阱不能简单地共享std::thread对象。

使用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陷入僵局之后,或者有时是核心转储。

1 个答案:

答案 0 :(得分:2)

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

你正确地指出继承自std::thread是一个坏主意(没有虚拟析构函数是一个死的赠品)我会争辩说,拥有多态线程类型并不是最聪明的设计,但如果你愿意,可以轻松地将std::thread封装为任何类的成员(多态或非多态)。

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

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

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

等等。所有的部件都在那里,你只需要根据你的需要进行组装。