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

Deadly 提交于 2020-01-15 09:06:51

问题


Hi have need to do some socket communication from background, I used QtConcurrent::run to this, but giving me the warning.

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)

Here is the code,

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);
     }
 }

How can I remove the warning?


回答1:


First, what is wrong with your code:

You cannot use this in new QTcpSocket(this), because this->thread() is not the current thread (QThread::currentThread()).

You cannot call any function member of socket after socket->moveToThread(this->thread()), because socket->thead() is not the current thread anymore.

This is documented here:

Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread.

Now, what you can do to fix your code if you just want to connect a TCP socket and do nothing more is to remove any reference to this and do something like that:

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);
     }
 }

But, if you want to do something else with the TCP socket like sending or receiving data, you'd be better wrapping up your code in a class:

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;
}

This way you can have all the TCP stuff (monitoring, data transfer, etc.) ins a single object. You can have it in the same thread than your MainWindow, but you can also have it in another thread if needed.

Note that if you have the CamWatcher in another thread than MainWindow, but you want to call functions of CamWatcher you have to do something like this:

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



回答2:


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

QFuture runs the &MainWindow::checkCamStatus function on a different thread.

When you create the new socket in the checkCamStatus function it happens on a different thread. You should create your socket outside the checkCamStatus function.

Alternatively you can modify your existing code to avoid a complete refactor like this:

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

But this alternative solution is less elegant.



来源:https://stackoverflow.com/questions/47449312/qobject-cannot-create-children-for-a-parent-that-is-in-a-different-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!