简体   繁体   English

我不确定为什么我的QThread模式被阻止

[英]I'm not sure why my QThread pattern is blocking

I've seen many posts and articles on QThread and moving QObjects between QThreads but alas, its still causing me headaches. 我看过许多关于QThread的文章和文章,以及在QThreads之间移动QObject的方法,但是可惜,这仍然让我头疼。 This is the pattern I'm trying to adopt: 这是我尝试采用的模式:

#include "connectionthread.h"
#include <cassert>

ConnectionThread::ConnectionThread(ConnectionPtr const &connectionPtr) :
                               worker(NULL),
                               m_connectionPtr(connectionPtr)
{
    connect(this, SIGNAL(executeSignal()), this, SLOT(loginProcess()));
}

void
ConnectionThread::start()
{
    if(worker) {
        if(worker->isRunning()) {
            worker->quit();
        }
        delete worker;
    }
    worker = new QThread;
    connect(worker, SIGNAL(started()), this, SLOT(run()));
    worker->start();
}

void
ConnectionThread::run()
{
    emit executeSignal();
}

void
ConnectionThread::loginProcess()
{
    m_connectionPtr->Connect();
}

Now an instance of this is created in the main GUI thread, yet when loginProcess is finally called, it blocks until completion which causes my app's GUI to hang. 现在,在主GUI线程中创建了此实例,但是最终调用loginProcess时,它将阻塞直到完成,这会导致我的应用的GUI挂起。 Note, no difference is observed if I put the logic code directly into the run function and omit the signal like as follows:- 请注意,如果将逻辑代码直接放入运行函数并忽略信号,则不会有任何区别,如下所示:

void
ConnectionThread::run() 
{
    m_connectionPtr->Connect();
}

So I assumed that I need to move 'this' to the thread named worker, something like: 所以我假设我需要将“ this”移动到名为worker的线程中,例如:

void
ConnectionThread::start()
{
    if(worker) {
        if(worker->isRunning()) {
            worker->quit();
        }
        delete worker;
    }
    worker = new QThread;
    this->moveToThread(worker);
    connect(worker, SIGNAL(started()), this, SLOT(run()));
    worker->start();
}

but this gives me 但这给了我

QObject: Cannot create children for a parent that is in a different thread.

I'm not sure why this is the case however since an instance of ConnectionThread is created and its start function is called from another thread. 我不确定为什么会这样,因为创建了ConnectionThread的实例,并从另一个线程调用了它的启动函数。 Let's call this other thread GuiThread. 我们将此线程称为GuiThread。 This means that GuiThread has control so should be able to transfer ownership of the ConnectionThread instance to the worker thread. 这意味着GuiThread拥有控制权,因此应该能够将ConnectionThread实例的所有权转移到工作线程。

One final possibility which I haven't fully explored yet is the possibility of moving m_connectionPtr to the worker thread.. 我尚未完全探讨的最后一种可能性是将m_connectionPtr移至工作线程的可能性。

Any thoughts on the above pattern, how I might improve it, and generally how I can prevent it from blocking? 对上述模式有什么想法,如何改进以及通常如何防止它受阻?

EDIT 1: The following was my proposed solution but it doesn't actually work as expected because the finished() signal is never being emitted by worker 编辑1:以下是我提出的解决方案,但它实际上并没有按预期方式工作,因为finish()信号永远不会由工作人员发出

EDIT 2: fixed the finished signal being triggered but I still can't move m_connectionPtr back to the main thread within the moveConnectionPtrBack. 编辑2:修复了已完成的信号被触发,但我仍然无法将m_connectionPtr移回到moveConnectionPtrBack中的主线程中。 Gives error "QObject::moveToThread: Current thread (0x102900380) is not the object's thread (0x10493b740). Cannot move to target thread (0x102900380)" 给出错误“ QObject :: moveToThread:当前线程(0x102900380)不是对象的线程(0x10493b740)。无法移动到目标线程(0x102900380)”

So, I think I've figured out what to do: the solution it seems was to transfer thread ownership of the ConnectionPtr to the worker thread: 因此,我认为我已经弄清楚该怎么做:解决方案似乎是将ConnectionPtr的线程所有权转移到工作线程:

#include "connectionthread.h"

ConnectionThread::ConnectionThread(ConnectionPtr const &connectionPtr) :
                               worker(NULL),
                               m_connectionPtr(connectionPtr)
{
    // EDIT 2 added bit -- m_connectionPtr sends signal when work finished
    connect(m_connectionPtr.data(), 
            SIGNAL(connectFinishedSignal()), this, SLOT(quitThread()));
}

void
ConnectionThread::start()
{
    if(worker) {
        if(worker->isRunning()) {
            worker->quit();
        }
        delete worker;
    }
    worker = new QThread;
    m_connectionPtr->moveToThread(worker);
    connect(worker, SIGNAL(started()), m_connectionPtr.data(), SLOT(Connect()));
    connect(worker, SIGNAL(finished()), this, SLOT(moveConnectionPtrBack()));
    worker->start();
}

void
ConnectionThread::moveConnectionPtrBack()
{
    // this call failing still
    m_connectionPtr->moveToThread(QApplication::instance()->thread());
}

// EDIT 2 added bit; quitting causes worker to send finished signal() which causes
// correct triggering of moveConnectionPtrBack() function
void
ConnectionThread::quitThread()
{
    worker->quit();
}

(Note m_connectionPtr is a shared ptr to a 'Connection' which itself is derived from a QObject but has no parent; likewise ConnectionThread is derived from a QObject but again, has no parent). (注意,m_connectionPtr是“连接”的共享ptr,“连接”本身是从QObject派生的,但没有父级;同样,ConnectionThread是从QObject派生的,但又没有父级)。

Since m_connectionPtr is also used by other threads in future, I also had to move it back again to the main thread as shown by the moveConnectionPtrBack slot. 由于将来其他线程也会使用m_connectionPtr,因此我还必须将其再次移回主线程,如moveConnectionPtrBack插槽所示。

Seems to do the trick but overall is not entirely bug-free. 似乎可以解决问题,但总体而言并非完全没有错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM