QObject无法为位于不同线程

时间:2017-11-23 06:55:36

标签: qt qthread qtconcurrent

您需要从后台进行一些套接字通信,我使用了QtConcurrent::run,但是给了我警告。

QObject: Cannot create children for a parent that is in a different thread.
(Parent is MainWindow(0x7fff3e69f500), parent's thread is QThread(0x16f8070), current thread is QThread(0x17413d0)

这是代码,

MainWindow::MainWindow(QWidget *parent) :
 QMainWindow(parent),ui(new Ui::MainWindow){
      ui->setupUi(this);
      QFuture<void> f2 = QtConcurrent::run(this,&MainWindow::checkCamStatus);
  }


 void MainWindow::checkCamStatus(){
     while(1){
       bool flag = false;
       QTcpSocket* socket = new QTcpSocket(this);
       socket->moveToThread(this->thread());
       socket->setParent(this);
       socket->connectToHost("10.0.7.112", 80);
       if(socket->waitForConnected(1000))//check for connection for i second
       {
         qDebug() << "Cam online";
       }
       else{
         qDebug() << "..............................Cam offline";
       }

       QThread::sleep(1);
     }
 }

如何删除警告?

2 个答案:

答案 0 :(得分:2)

首先,您的代码有什么问题:

您无法在this中使用new QTcpSocket(this),因为this->thread()不是当前主题(QThread::currentThread())。

socket之后,您无法调用socket->moveToThread(this->thread())的任何功能成员,因为socket->thead()不再是当前主题。

记录在案here

  

事件驱动对象只能在单个线程中使用。   具体而言,这适用于计时器机制和网络   模块即可。例如,您无法启动计时器或连接套接字   不是对象线程的线程。

现在,如果您只想连接TCP套接字而不做更多其他操作,那么您可以采取哪些措施来修复代码,即删除对this的任何引用并执行类似的操作:

void MainWindow::checkCamStatus(){
     while(1){
       bool flag = false;
       QScopedPointer<QTcpSocket> socket(new QTcpSocket()); 
       socket->connectToHost("10.0.7.112", 80);
       if(socket->waitForConnected(1000))//check for connection for i second
       {
         qDebug() << "Cam online";
       }
       else{
         qDebug() << "..............................Cam offline";
       }

       QThread::sleep(1);
     }
 }

但是,如果您想使用TCP套接字执行其他操作,例如发送或接收数据,那么您最好在类中包装代码:

class CamWatcher : public QObject
{
    Q_OBJECT
public:
    CamWatcher(QObject *parent = 0) :
        QObject(parent),
        m_socket(new QTcpSocket(this))
    {}
    QTcpSocket *socket() { return m_socket; }

public slots:
    void tryConnect() { socket->connectToHost("10.0.7.112", 80); }

private slots:
    void onSocketConnected() { qDebug() << "Connected"; }
    void onSocketDisconnected()  { qDebug() << "Disconnected"; }
    void onSocketError(QAbstractSocket::SocketError socketError)
    {
        qWarning() << m_socket->errorString();
    }
private:
    QTcpSocket *m_socket = nullptr;
}

通过这种方式,您可以将所有TCP内容(监视,数据传输等)放在一个对象中。您可以在与MainWindow相同的线程中使用它,但如果需要,您也可以在另一个线程中使用它。

请注意,如果您在另一个线程中使用CamWatcher而不是MainWindow,但是您想调用CamWatcher的函数,则必须执行以下操作:

QTimer::singleshot(0, camwatcher, &CamWatcher::tryConnect);
QMetaObject::invokeMethod(camwatcher, "tryConnect", Qt::QueuedConnection); // No compile time check, works only with slots
QMetaObject::invokeMethod(camwatcher, &CamWatcher::tryConnect, Qt::QueuedConnection); // Requires Qt 5.10

答案 1 :(得分:1)

QFuture<void> f2 = QtConcurrent::run(this,&MainWindow::checkCamStatus);

QFuture在另一个线程上运行&MainWindow::checkCamStatus函数。

checkCamStatus函数中创建新套接字时,它发生在另一个线程上。您应该在checkCamStatus函数之外创建套接字。

或者,您可以修改现有代码以避免像这样的完整重构:

QTcpSocket* socket = new QTcpSocket(); // Remove the parent from here
socket->moveToThread(this->thread());  // Move socket back to the original thread
socket->setParent(this);               // Set socket's parent here, this and socket are now on the same thread

但这种替代解决方案并不那么优雅。