问题
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