我有一个GUI的主线程,其中运行MainWindow
对象,
在它的构造函数中,我创建了一个新的worker对象和一个QThread
对象,我将工作者移动到线程,问题是当打印它们的id时它们是相同的:
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
QThread *t_pc = new QThread;
worker *pc_w;
pc_w = new pc_worker();
pc_w->moveToThread(t_pc);
t_pc->start();
pc_w->initialize();
// ...
}
worker.cpp
worker::worker(QObject *parent) : QObject(parent) {
}
void worker::initialize() {
std::cout << "INITIALIZE " << QThread::currentThreadId() << std::endl;
}
我明白了:
MAIN_ID 0x7f4009ccb780
INITIALIZE 0x7f4009ccb780
怎么了?
答案 0 :(得分:2)
答案:moveToThread
工作,只是没有达到预期的效果。
在调用pc_w->moveToThread(t_pc)
之后,您希望现在可以在pc_w
中调用t_pc
的所有成员函数。但是,这不是moveToThread()
所做的。
moveToThread()
的目的是更改QObject
“线程关联”或者换句话说是对象所在的线程。 但在基本级别上它给你的一切只是保证通过Qt::QueuedConnection
连接到任何信号的所有对象插槽将被调用(运行)在那个特定的线程中。
成员函数仍然在您调用它们的线程中运行。在您的情况下,您从GUI线程中调用initialize()
,因此QThread::currentThreadId()
为您提供该线程的 id 。
我真的建议在线程事件循环上阅读关于thread affinity和this article的官方文档。
QThread* thread = new QThread;
Worker* worker = new Worker;
// Uses Qt::AutoConnection (default)
// which will be transalted into Qt::QueuedConnection
QObject::connect(thread, &QThread::started, worker, &Worker::initialize);
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
worker->moveToThread(thread);
thread->start();
输出:
MAIN_ID 0000000000003E5C
INITIALIZE 0000000000003DAC
解决方案 trivelt 提议人为地将“call initialize()
”事件放入线程事件循环中,达到相同的效果。但是,它不执行任何编译时检查(“initialize”指定为字符串)。
答案 1 :(得分:0)
尝试使用invokeMethod
代替直接调用pc_w->initialize()
,例如:
QMetaObject::invokeMethod(pc_w, "initialize", Qt::QueuedConnection);
在这种情况下,您的initialize()
方法应为SLOT或SIGNAL。