我有一个从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()不能工作。
我修正了一个关于插槽名的错误。
发布于 2014-08-12 14:46:14
一个非常可能的可能性是,您正在执行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对象,因此需要保护对该对象部分的每次访问/写入。
发布于 2014-08-12 14:41:19
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();来运行,要么重新设计该工作,以便由事件循环中的一系列调用来处理。
发布于 2014-08-12 14:24:33
在Uploader类中,将槽标记为: void finishedWhenQueueIsEmpty();
然后你打电话:-
connect(this, SIGNAL(allWorkDone()), uploader, SLOT(finishWhenQueueIsEmpty()));其中之一是“finishWhen.”还有另一个‘finishedWhen.’
如果使用此connect语法(PreQT5.0),则可以检查connect调用的返回值,或者至少在调试器中运行时查看调试输出,调试器会告诉您插槽无效。
使用Qt5连接语法,可以在编译时捕捉到这一点:-
connect(this, &UploadWorker::allWorkDone() uploader, &Uploader::finishWhenQueueIsEmpty());https://stackoverflow.com/questions/25266794
复制相似问题