首页 > 解决方案 > 对象:无法为位于不同线程中的父级创建子级

问题描述

我正在使用:

Qt Creator 3.0.1
Based on Qt 5.2.1 (GCC 4.8.2, 32 bit)
Built on Apr 9 2014 at 09:14:10

此版本是 ACR890 一体化移动智能卡终端 SDK 的一部分。

手机正在运行 linux,我不是发行版,如果我运行:

uname -a:

我得到:

Linux am37x-evm 2.6.37 #1 Wed Nov 22 18:16:43 HKT 2017 armv7l GNU/Linux

在我的应用程序中,我创建了一个工作线程来检查 WiFi 网络的状态:

mpWiFiScan = new clsWiFiScan(this);
//Connect slot to scan signal
connect(mpWiFiScan, SIGNAL(scanResultsReady(QString))
           ,this, SLOT(networkScanResults(QString)));
mpWiFiScan->setScanState(SS_SCAN);
mpWiFiScan->start();

这在主窗口构造函数的末尾被调用。在主窗口类中,我有接收网络扫描结果的插槽:

void clsMainWnd::networkScanResults(QString strResults) {
    qDebug() << "clsMainWnd::networkScanResults:";
    qDebug() << strResults;
}

这是 WiFi 扫描线程主体:

void clsWiFiScan::run() {
    int intSleepCounter = 0;
    bool blnLastPowerState;
    QString strResponse;

    while ( true ) {
        eScanState eState = eGetScanState();

        if ( eState == SS_TERMINATE ) {
            break;
        }
        if ( eState != SS_SCAN ) {
            continue;
        }
        bool blnPower = blnGetPowerStatus();

        if ( blnPower != true ) {
    //Is the "wpa_supplicant" process running?
            if ( clsSOAP::lngPIDof(this, lsWiFiScan::mscstrWPAsupplicant) == 0 ) {
    //No, start it now
                mpcAcsWiFi->reloadWpaSupplicant();
            }
    //Can we ping Google?
            if ( clsSOAP::blnPingTest(this) != true ) {
    //No, ensure WiFi power is on
                wifi_pwr_on();
            }
    //Can we get a server response?
            strResponse = mpcAcsWiFi->status();

            if ( strResponse.contains("wpa_state=COMPLETED") ) {
    //Yes, turn on power
                setPower(true);
            }
            while ( eState != SS_TERMINATE
                 && eState != SS_PAUSE
                 && intSleepCounter < mscintReloadWPAsupplicantTime) {
                sleep(mscintTempSleepDuration);
                intSleepCounter += mscintTempSleepDuration;
                eState = eGetScanState();
            }
            if ( intSleepCounter == mscintReloadWPAsupplicantTime ) {
                setPower(true);
            }
            intSleepCounter = 0;
        }
    //If the power was off and now its on...
        if ( blnLastPowerState != true && blnGetPowerStatus() == true ) {
            mpcAcsWiFi->scan();
            strResponse = mpcAcsWiFi->scanResults();
            emit scanResultsReady(strResponse);

            while ( eState != SS_TERMINATE
                 && eState != SS_PAUSE
                 && intSleepCounter < mscintScanInterval ) {
                sleep(mscintTempSleepDuration);
                intSleepCounter += mscintTempSleepDuration;
                eState = eGetScanState();
            }
        }
    //Update the last known power state
        blnLastPowerState = blnPower;
        intSleepCounter = 0;
    }
    emit scanFinished();
    delete mpcAcsWiFi;
    setScanState(SS_TERMINATED);
}

问题是当我运行这个应用程序时,我会看到很多以下内容:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is clsWiFiScan(0xd8208), parent's thread is Thread(0xb8c38), current thread is clsWiFiScan(0xd8208)

然后后来:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QProcess(0xd82e8), parent's thread is Thread(0xb8c38), current thread is clsWiFiScan(0xd8208)

QProcess 在函数中被调用:

bool clsSOAP::blnPingTest(QObject* pParent, QString strURL) {
    QProcess* pProc = new QProcess(pParent);
    pProc->start("ping", QStringList() << "-c" << "1" <<
                                          "-w" << "10" <<
                                          strURL);
    while( pProc->waitForFinished() != true ) {
    }
    int intExitCode = pProc->exitCode();
    delete pProc;
    return (intExitCode == 0);
}

对于 Google,strURL 的默认值为 8.8.8.8。

long clsSOAP::lngPIDof(QObject* pParent, QString strApp) {
    QProcess* pProc = new QProcess(pParent);
    pProc->start("pidof", QStringList() << strApp);
    while( pProc->waitForFinished() != true ) {
    }
    QByteArray bytOutput = pProc->readAllStandardOutput();
    bool blnOk;
    long lngPID = bytOutput.trimmed().toLong(&blnOk);
    delete pProc;
    return lngPID;
}

一切似乎都正常,但我仍然收到很多这些警告。

[编辑] 根据评论,我更改了我的类,因此它现在派生自 QObject,而不是 QThread。

现在是这样写的:

mpWiFiScan = new clsWiFiScan(this);
//In the clsWiFiScan constructor it calls setParent(pParent); where pParent the passed parameter
mpWiFiScan->moveToThread(&mthrdWiFiScan);
//mthrdWiFiScan is a member variable of type QThread
connect(&mthrdWiFiScan, SIGNAL(started())
       ,mpWiFiScan, SLOT(run()));
connect(mpWiFiScan, SIGNAL(scanFinished())
       ,&mthrdWiFiScan, SLOT(quit()));
connect(mpWiFiScan, SIGNAL(scanFinished())
       ,&mthrdWiFiScan, SLOT(deleteLater()));
connect(&mthrdWiFiScan, SIGNAL(finished())
       ,&mthrdWiFiScan, SLOT(deleteLater()));
mthrdWiFiScan.start();

我仍然收到相同的消息,我根本没有看到 run() 被调用。

标签: c++qt

解决方案


您可以通过调用QObject::moveToThread()然后设置父对象来解决这些问题。

例如,您创建 WiFi 扫描仪的代码会像这样改变。

mpWiFiScan = new clsWiFiScan();
mpWiFiScan->moveToThread(QApplication::instance()->thread());
mpWiFiScan->setParent(this);
//Connect slot to scan signal
connect(mpWiFiScan, SIGNAL(scanResultsReady(QString))
       ,this, SLOT(networkScanResults(QString)));
mpWiFiScan->setScanState(SS_SCAN);
mpWiFiScan->start();

推荐阅读