QObject 无法为处于不同线程中的父对象创建子对象
QObject Cannot create children for a parent that is in a different thread
您好,我需要从后台进行一些套接字通信,我对此使用了 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);
}
}
如何删除警告?
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
但是这个替代解决方案不太优雅。
首先,你的代码有什么问题:
您不能在 new QTcpSocket(this)
中使用 this
,因为 this->thread()
不是当前线程 (QThread::currentThread()
)。
您不能在 socket->moveToThread(this->thread())
之后调用 socket
的任何函数成员,因为 socket->thead()
不再是当前线程。
这已记录在案 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.
现在,如果您只想连接一个 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:
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 放在同一个线程中,但如果需要,您也可以将它放在另一个线程中。
请注意,如果您在 MainWindow 之外的另一个线程中有 CamWatcher,但您想要调用 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
您好,我需要从后台进行一些套接字通信,我对此使用了 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);
}
}
如何删除警告?
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
但是这个替代解决方案不太优雅。
首先,你的代码有什么问题:
您不能在 new QTcpSocket(this)
中使用 this
,因为 this->thread()
不是当前线程 (QThread::currentThread()
)。
您不能在 socket->moveToThread(this->thread())
之后调用 socket
的任何函数成员,因为 socket->thead()
不再是当前线程。
这已记录在案 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.
现在,如果您只想连接一个 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:
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 放在同一个线程中,但如果需要,您也可以将它放在另一个线程中。
请注意,如果您在 MainWindow 之外的另一个线程中有 CamWatcher,但您想要调用 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