Qt 4.8 在 moveToThread() 之后未调用的信号/插槽
Qt 4.8 Signals/Slots not called after moveToThread()
我有一个派生自QObject
的类,UploadWorker
,它已经使用Qt文档中演示的推荐的在线程中运行任务的方式启动。
QThread* thread = new QThread();
UploadWorker* worker = new UploadWorker();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(doWork()));
现在,这工作得很好。然后,我的UploadWorker
尝试使用相同的技术为自己启动一个名为Uploader
的工人。
以下是标头的必要部分。
class UploadWorker : public QObject
{
Q_OBJECT
public:
// stuff
public slots:
void doWork();
signals:
void allWorkDone();
protected:
void startUploader();
};
class Uploader : public QObject
{
Q_OBJECT
public:
// stuff
public slots:
void doWork();
void finishWhenQueueIsEmpty();
};
这是UploadWorker
的实现。
void
UploadWorker::doWork()
{
// This method is called when QThread emits started()
// Prepare the upload thread
startUploader();
// Do some important work...
// Notify the upload thread that we're done
emit allWorkDone();
}
void
UploadWorker::startUploader()
{
QThread* thread = new QThread();
Uploader* uploader = new Uploader();
uploader->moveToThread(thread);
connect(this, SIGNAL(stopped()), uploader, SLOT(stop()));
connect(uploader, SIGNAL(finished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(uploader, SIGNAL(finished()), uploader, SLOT(deleteLater()));
connect(thread, SIGNAL(started()), uploader, SLOT(doWork()));
connect(this, SIGNAL(allWorkDone()),
uploader, SLOT(finishWhenQueueIsEmpty()));
thread->start();
}
我现在的问题是,Uploader::finishWhenQueueIsEmpty()
槽永远不会被触发。除非:我删除uploader->moveToThread(thread);
.
错误在哪里?
编辑我忘了提到线程启动时调用Uploader::doWork()
方法。在此示例中,它是任何其他不起作用的插槽finishWhenQueueIsEmpty()
。
我修复了有关插槽名称的拼写错误。
一种非常可能的可能性是,您正在执行Uploader::doWork()
槽,并通过某种同步机制(例如布尔isRunning
(等待对时隙Uploader::finishWhenQueueIsEmpty()
的调用来完成其执行。
然后,您需要做的是像下面这样连接插槽:
connect(this, SIGNAL(allWorkDone()),
uploader, SLOT(finishWhenQueueIsEmpty()),
Qt::DirectConnection);
并finishWhenQueueIsEmpty()
使用互斥锁保护同步机制。
为什么?
因为在不同线程中的对象之间建立连接的默认模式是 Qt::QueuedConnection
。它在这里所做的是,这里的 Uploader
类的每个插槽都排队等待执行,也就是说,一旦线程返回到事件循环(即当前插槽完成运行(,队列中的下一个插槽就会运行。然后,这意味着在这种模式下,调用Uploader::doWork()
然后调用Uploader::finishWhenQueueIsEmpty()
将导致程序卡在doWork()
中。
使用Qt::DirectConnection
,插槽将在运行UploaderWorker::doWork()
的线程中运行,并且实际上可以在Uploader::doWork()
运行时运行。但是,您有两个线程可以访问同一个Uploader
对象,因此您需要保护对该对象部分的每次访问/写入。
void
UploadWorker::doWork()
{
// This method is called when QThread emits started()
// Prepare the upload thread
startUploader();
// Do some important work...
// Notify the upload thread that we're done
emit allWorkDone();
}
这里的结构告诉我,在你实际完成"重要工作"之前,你不会让事件循环运行,这意味着不会触发任何插槽。
要么通过定期调用QApplication::processEvents();
来运行事件,要么重新设计工作,以便由事件循环中的一系列调用来处理它。
在 Uploader 类中,您标记了插槽:void doneWhenQueueIsEmpty((;
然后你打电话:-
connect(this, SIGNAL(allWorkDone()), uploader, SLOT(finishWhenQueueIsEmpty()));
所以一个是"完成何时..."另一个"完成时间"。
如果您使用此连接语法(Qt 5.0 之前(,那么您可以检查连接调用的返回值,或者至少在调试器中运行时查看调试输出,这将告诉您该槽无效。
使用Qt 5连接语法,可以在编译时捕获:
connect(this, &UploadWorker::allWorkDone() uploader, &Uploader::finishWhenQueueIsEmpty());
- Qt信号和插槽如果从QRunnable或其他线程调用,则不起作用
- QNetworkReply::done() 信号是按顺序调用还是同时调用?
- 当再次触发信号时,从Qt插槽执行的功能被第二次调用时会发生什么?
- C++发出信号稍后在 QML 中调用
- 从 Qt 中的信号调用成员函数的问题
- 当对话框中的任何小部件发出信号时,是否可以调用插槽
- 这是在Qt信号和插槽中使用参数调用函数的好方法吗?
- 从第二个线程调用Qt信号有效 - >对连接的插槽没有影响
- 如何使用unique_ptr声明调用构造函数并处理程序终止信号
- 如何使 WaitForSingleObject 在从 main 调用的线程内接收信号作为类成员函数
- 无法从抽象类调用按钮信号
- 如果不同的线程调用另一个不同线程的相同信号,则需要静音
- 当 epoll 发出活动信号时,recv() 调用怎么会阻塞
- Qt connect(*发送器,*信号,*接收器,*方法)不调用插槽
- 在调用stop()之后,将发送qTimer超时信号
- 程序在调用类指针时收到信号SIGSEGV,分段错误
- 被信号中断的系统调用仍然需要完成
- 使用发出与调用信号,就好像它是Qt中的常规函数一样
- 如何防止QPushButton调用信号两次
- 无法调用C信号方法中的类方法