首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QT4.8信号/插槽未在moveToThread()之后调用

QT4.8信号/插槽未在moveToThread()之后调用
EN

Stack Overflow用户
提问于 2014-08-12 14:22:39
回答 3查看 3.5K关注 0票数 5

我有一个从QObject派生的类,UploadWorker,它是使用推荐的在线程中运行任务的方式启动的,如Qt文档所示。

代码语言:javascript
复制
QThread*      thread = new QThread();
UploadWorker* worker = new UploadWorker();

worker->moveToThread(thread);

connect(thread, SIGNAL(started()), worker, SLOT(doWork()));

现在,这一切都很好。然后,我的UploadWorker尝试使用相同的技术为自己启动一个名为Uploader的工作人员。

以下是标题的必要部分。

代码语言:javascript
复制
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的实现。

代码语言:javascript
复制
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()不能工作。

我修正了一个关于插槽名的错误。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-08-12 14:46:14

一个非常可能的可能性是,您正在执行Uploader::doWork()插槽,并等待通过某种同步机制(例如布尔isRunning )调用时隙Uploader::finishWhenQueueIsEmpty()来完成它的执行。

然后,您需要做的是像下面这样连接您的插槽:

代码语言:javascript
复制
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对象,因此需要保护对该对象部分的每次访问/写入。

票数 10
EN

Stack Overflow用户

发布于 2014-08-12 14:41:19

代码语言:javascript
复制
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();来运行,要么重新设计该工作,以便由事件循环中的一系列调用来处理。

票数 3
EN

Stack Overflow用户

发布于 2014-08-12 14:24:33

在Uploader类中,将槽标记为: void finishedWhenQueueIsEmpty();

然后你打电话:-

代码语言:javascript
复制
connect(this, SIGNAL(allWorkDone()), uploader, SLOT(finishWhenQueueIsEmpty()));

其中之一是“finishWhen.”还有另一个‘finishedWhen.’

如果使用此connect语法(PreQT5.0),则可以检查connect调用的返回值,或者至少在调试器中运行时查看调试输出,调试器会告诉您插槽无效。

使用Qt5连接语法,可以在编译时捕捉到这一点:-

代码语言:javascript
复制
connect(this, &UploadWorker::allWorkDone() uploader, &Uploader::finishWhenQueueIsEmpty());
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25266794

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档