在QThread的上下文中调用方法
-
06-07-2019 - |
题
在我的应用程序中有主线程和工作线程( QThread
)。
从主线程我想调用我的工作线程的方法,让它在线程的上下文中运行。
我尝试使用 QMetaObject :: invokeMethod
并为其提供 QueuedConnection
选项,但它不起作用。
我也尝试从主线程(连接到工作线程的插槽)发出信号,但也失败了。
以下是我尝试过的一小段内容:
class Worker : public QThread
{
Q_OBJECT
public:
Worker() { }
void run()
{
qDebug() << "new thread id " << QThread::currentThreadId();
exec();
}
public slots:
void doWork()
{
qDebug() << "executing thread id - " << QThread::currentThreadId();
}
};
使用QMetaObject方式:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "main thread id - " << QThread::currentThreadId();
Worker worker;
worker.start();
QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);
return a.exec();
}
使用信号方式:
class Dummy : public QObject
{
Q_OBJECT
public:
Dummy() { }
public slots:
void askWork() { emit work(); }
signals:
void work();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "main thread id - " << QThread::currentThreadId();
Worker worker;
worker.start();
Dummy dummy;
QObject::connect(&dummy, SIGNAL(work()), &worker, SLOT(doWork()), Qt::QueuedConnection);
QTimer::singleShot(1000, &dummy, SLOT(askWork()));
return a.exec();
}
两种方式都会导致主线程id被打印在 QThread
doWork
中。
另外,我想过实现一个简单的生产者 - 消费者,但是如果这样做,有什么理由不这样做吗?
解决方案
问题是接收者(QThread)'生活'在主线程中,因此主线程的事件循环是执行槽的那个。
来自Qt的文档:
对于排队连接,当控制返回到对象所属线程的事件循环时,将调用该槽。插槽在接收器对象所在的线程中执行。
所以我到目前为止找到的解决方案是在线程的run()中创建一个对象,然后使用它的槽。这样接收者的所有者就是线程,然后在线程上下文中调用插槽。
其他提示
此示例显示了如何拆分Worker类,使其按您的意愿工作。您还需要提供一个指向Worker实例的引用或指针,以便能够连接到插槽。
class Worker : public QObject
{
Q_OBJECT
public:
Worker() { }
public slots:
void doWork()
{
qDebug() << "executing thread id - " << QThread::currentThreadId();
}
};
class WorkerThread : public QThread
{
Q_OBJECT
public:
void run()
{
qDebug() << "new thread id " << QThread::currentThreadId();
Worker worker;
exec();
}
};
对于简单的生产者 - 消费者示例,请查看Bradley T. Hughes的博客条目没有头痛的行走。
Worker在主线程中创建,因此它的事件在主线程中被占用。您必须将Worker移动到它自己的线程:
Worker worker;
worker.moveToThread(&worker);
worker.start();
现在Qt知道 worker
存在于新线程中,并将在该事件循环中对事件进行排队。
在您甚至可以调用任何函数或向其发送信号之前,看起来您的工作线程已完成。
不隶属于 StackOverflow