QThread 对象作为工作类的成员
Posted
技术标签:
【中文标题】QThread 对象作为工作类的成员【英文标题】:QThread object as a member of worker class 【发布时间】:2016-04-04 13:24:14 【问题描述】:我已经阅读了很多关于为什么在大多数情况下子类化QThread
是一个坏主意以及如何正确使用QThread
的文章,调用moveToThread
方法。 Here我们可以看到这种设计的典型例子。
我正在设计的班级应该满足以下要求:
它想使用信号和槽,所以我需要一个事件循环并使用moveToThread
。
它将仅公开带有信号和插槽的接口。没有普通的 C++ 方法。
所有槽都应该在对象的专用线程中执行,每个对象一个线程。所以线程应该在创建对象时创建,并且应该在对象死亡时结束。
因此想到了一个明显的解决方案(未经测试,只是一个草图代码):
class Worker : public QObject
Q_OBJECT
public:
Worker()
thread = new QThread();
// ...Some signal-slot connections may be done here...
// ...Some other connections may be performed by user code...
moveToThread(thread);
thread->start();
~Worker()
thread->exit();
thread->wait();
delete thread;
public slots:
void process(); // and other interface slots
signals:
// Interface signals
private:
QThread* thread;
;
所以重点是将QThread
对象声明为工人类的(私有)成员,但我从未在任何示例或其他人的代码中看到过。
这就是为什么我想知道这个设计是否有缺陷?它有一些我没有注意到的致命缺点吗?或者没关系,只是不经常需要?
【问题讨论】:
首先,使用某种 RAII 对象,例如(unique_ptr 等)。其次,这可能更适合 CodeReview SE 网站。 @OMGtechy 这可能会在 Code Review 上关闭,作者提到 “未测试,只是一个草图代码”。代码审查需要真实、有效的代码。看看那里是什么on-topic 以供参考。 @Phrancis 啊,在这种情况下,我建议先试试@Sergey! 未测试 - 如果您自己尝试一些事情,然后根据您的研究提出您不理解的问题,您将学到更多。 @OMGtechy 我看到这个问题在这个网站上有点离题。也许应该把它移到programmers.stackexchange.com? 【参考方案1】:只要将对象移出工作线程,这是可能的。以下是您可以这样做的方法 - 请注意,您应该按值保存线程,没有意义不使用编译器为您管理内存。
class Worker : public QObject
Q_OBJECT
QThread m_thread;
public:
Worker()
m_thread.start();
moveToThread(&m_thread);
~Worker()
// Move us out of any thread.
// moveToThread must always be called from QObject::thread()!
QObject sig;
sig.connect(&sig, &QObject::destroyed, this, [this]
this->moveToThread(0); // become thread-less
m_thread->quit();
);
// Wait for the thread to stop
m_thread.wait();
;
鉴于可以通过QtConcurrent::run
异步完成工作,您很可能无论如何都不应该使用这样的对象。最有可能的是,您将浪费大部分空闲的线程,因为您不太可能使线程始终可运行。不可运行的线程本质上是一种资源浪费。
【讨论】:
我想这段代码什么都不做:QThread * curThread = thread(); this->moveToThread(curThread);
。另外我认为没有必要在析构函数中使用线程更改技巧。哪个线程会销毁对象并不重要。
@hank 我认为代码是必要的,因为不能保证调用析构函数的线程是由 m_thread 处理的。官方文档 (doc.qt.io/qt-5/threads-qobject.html) 说“从拥有对象(或以其他方式访问对象)的线程以外的线程调用 QObject 上的删除是不安全的......”。
@Sergey “……不安全,除非你保证对象此时没有处理事件”。退出并停止线程后,对象不会处理任何事件。
@hank 该对象不处理任何事件,但object->thread()
非零且不同于QThread::currentThread()
。这表明不应访问对象的非线程安全方法。对于一个足够复杂的对象,上面介绍的方法确保该对象不会在其他线程中运行,无论出于何种原因。这可能是矫枉过正,但它是廉价的保证。以上是关于QThread 对象作为工作类的成员的主要内容,如果未能解决你的问题,请参考以下文章
如何使用cpp中的QThread使用一个对象运行同一类的两个线程?