您需要从后台进行一些套接字通信,我使用了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);
}
}
如何删除警告?
答案 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
但这种替代解决方案并不那么优雅。