QThread - 使用 moveToThread 将类成员移动到线程
Posted
技术标签:
【中文标题】QThread - 使用 moveToThread 将类成员移动到线程【英文标题】:QThread - Move class member to thread using moveToThread 【发布时间】:2013-10-27 17:43:57 【问题描述】:我从多线程开始,将对象移动到 QThread 时遇到了一些麻烦。我的 Controller 类实例化 Worker,为 Worker 创建必要的线程并将 Worker 移动到新线程。当工作线程启动时,工作线程上的计算就开始了。 Worker 类包含一个 Dummy 对象,在 worker 计算期间使用(函数 Dummy::doDummyStuff()
)。一切似乎都运行良好,除了 doDummyStuff()
似乎在主(控制器)线程而不是工作线程中执行。这是因为 Worker 对象(以及因此 Dummy 对象)是首先在主线程中创建的吗?有没有办法在工作线程中移动 Worker 对象的所有类成员?
这是一个代码 sn-p :
控制器.h
class Controller: public QObject
Q_OBJECT
public:
Controller(std::vector<double> _data, QString _fn);
void startControl();
private:
QThread workerThread_;
Worker worker_;
PostProcessing postProc_;
;
控制器.cpp
Controller::Controller(std::vector<double> _data, QString _fn): QObject(), workerThread_(), worker_(_data), postProc_()
QObject::connect(&workerThread_, SIGNAL(started()), &worker_, SLOT(doWork()));
QObject::connect(&worker_, SIGNAL(signalResultReady(double)), &postProc_, SLOT(update(double)));
void Controller::startControl()
worker_.moveToThread(&workerThread_);
workerThread_.start();
工人.h
class Worker: public QObject
Q_OBJECT
public:
Worker(std::vector<double> _coord);
signals:
void signalResultReady(double);
public slots:
void doWork();
private:
double res_;
std::vector<double> coord_;
Dummy dummyCreatedInWorker_;
;
工人.cpp
Worker::Worker(std::vector<double> _coord): QObject(), res_(0), coord_(_coord), dummyCreatedInWorker_()
void Worker::doWork()
qDebug() << "Worker thread ID" << this->thread();
for(unsigned int ii = 0; ii < coord_.size(); ii++)
res_ += coord_[ii];
dummyCreatedInWorker_.doDummyStuff();
emit signalResultReady(res_);
/* ....*/
Dummy::doDummyStuff
void Dummy::doDummyStuff()
qDebug() << "Doing dummy stuff from thread" << this->thread();
for(int ii = 0; ii < 10; ii++)
res_ += ii;
【问题讨论】:
doWork() 中的调试是否显示正确的线程?您直接从 doWork() 调用 doDummyStuff(),因此它将在与 doWork() 相同的线程中执行,独立于任何 QObject 线程关联。 是的,我在 doWork() 中获得了正确的线程 ID。正如 BeniBela 所指出的,我在 doDummyStuff() 中滥用了 this->thread。使用 QThread::currentThread() 返回正确的线程 ID。感谢您的回答! 如果this->thread()
不等于QThread::currentThread()
,您很可能会在代码中遇到错误,除非您已将QObject
明确设计为可从多个线程访问,并且被调用的方法对访问对象的数据有适当的同步保护。
【参考方案1】:
你的虚拟类也是从 QObject 派生的?
如果你将 dummy 设置为 worker 的子节点,那么当你调用 moveToThread 时它会自动移动。
即将 worker 传递给 dummy 的构造函数,如果它没有隐藏默认的 qobject 构造函数:
Worker::Worker(std::vector<double> _coord):
QObject(), res_(0), coord_(_coord), dummyCreatedInWorker_(this)
或者,您可以在工作人员和虚拟对象上调用 moveToThread。
但是,即使不做任何更改,Dummy::doDummyStuff()
也会在工作线程中被调用。
调用任何东西都不会改变线程,只会发出(排队)信号。
但是您不能使用this->thread()
来检查调用该方法的线程。它返回对象“驻留”的线程,即对象的(排队)槽将被调用的线程,如果被信号调用的话。
改为使用QThread::currentThread()
来查看调用方法的线程。
可以在任意线程中调用任意对象的任意方法,完全独立于对象与线程之间的关联
【讨论】:
确实,使用 QThread::currentThread() 返回正确的线程 ID。谢谢你的澄清!以上是关于QThread - 使用 moveToThread 将类成员移动到线程的主要内容,如果未能解决你的问题,请参考以下文章
重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)
Qt线程—QThread的使用--run和movetoThread的用法
QThread多线程编程经典案例分析(三种方法,解释了为什么使用moveToThread的根本原因,即为了避免调用QThread::exec() )