在我的应用程序中有主线程和工作线程(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
中打印。
另外,我想过实现一个简单的生产者 - 消费者,但是如果这样做,有什么理由不这样做吗?
答案 0 :(得分:3)
问题是接收者(QThread)'生活'在主线程中,因此主线程的事件循环是执行槽的那个。
来自Qt的文档:
对于排队连接,当控制返回到对象所属线程的事件循环时,将调用该槽。插槽在接收器对象所在的线程中执行。
所以我到目前为止找到的解决方案是在线程的run()中创建一个对象,然后使用它的槽。这样接收者的所有者就是线程,然后在线程上下文中调用插槽。
答案 1 :(得分:2)
对于简单的生产者 - 消费者示例,请查看Bradley T. Hughes Treading without the headache的博客条目。
答案 2 :(得分:2)
此示例显示了如何拆分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();
}
};
答案 3 :(得分:1)
Worker在主线程中创建,因此它的事件在主线程中被占用。您必须将Worker移动到它自己的线程:
Worker worker;
worker.moveToThread(&worker);
worker.start();
现在Qt知道worker
存在于新线程中,并将在该事件循环中对事件进行排队。
答案 4 :(得分:0)
在您甚至可以调用任何函数或向其发送信号之前,看起来您的工作线程已完成。