std::thread
不仅可以通过类继承,也不能在销毁时自动加入等。
当使用std::atomic_bool
作为成员变量执行成员方法时,需要使用this
进行停止等许多陷阱不能简单地共享std::thread
对象。
使用std::thread
我瞄准可继承的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
陷入僵局之后,或者有时是核心转储。
答案 0 :(得分:2)
std::thread
旨在作为实现线程原语的最低构建块。因此,它不提供与QThread一样丰富的接口,但与标准库中的同步原语一起,它允许您实现更复杂的行为,如QThread提供的非常容易。
你正确地指出继承自std::thread
是一个坏主意(没有虚拟析构函数是一个死的赠品)我会争辩说,拥有多态线程类型并不是最聪明的设计,但如果你愿意,可以轻松地将std::thread
封装为任何类的成员(多态或非多态)。
加入破坏实际上只是一项政策。封装std::thread
作为成员的类可以简单地在其析构函数中调用join
,从而有效地实现破坏时的自联接。并发性在这里无关紧要,因为根据定义,对象销毁总是非并发地执行。如果要在多个(可能同时调用的)执行路径之间共享线程的所有权,std::shared_ptr
将为您处理。但即使在这里,析构函数总是由放弃其shared_ptr
的最后一个剩余线程非并发执行。
QThread::isInterruptionRequested
之类的东西可以使用单个标志来实现,当然必须通过类同步访问(使用互斥锁或使用原子标记)。
标准未指定更改线程的优先级,因为并非标准所设想的所有平台都允许这样做,但您可以使用native_handle
自行使用特定于平台的代码来实现此功能。 / p>
等等。所有的部件都在那里,你只需要根据你的需要进行组装。