无法使用 QtNetwork,因为应用程序使用不同的线程

Posted

技术标签:

【中文标题】无法使用 QtNetwork,因为应用程序使用不同的线程【英文标题】:Cannot use QtNetwork because application uses different Threads 【发布时间】:2016-03-31 10:07:27 【问题描述】:

当我使用 QtNetwork 时,我的应用程序发生了奇怪的行为。我可以轻松地创建QTcpSeverQTcpSocket 实例并且一切运行正常,但是当涉及QTcpSocket::write() 时出现以下错误:

错误

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f66980022e0), parent's thread is QThread(0x7f66a0020be0), current thread is QThread(0x7f66a0020e20)
QSocketNotifier: Can only be used with threads started with QThread

我有什么奇怪的:我不知道这个QThread(0x7f66a0020e20) 是什么/在哪里以及如何影响它(看看下面的调试 )

计划

我正在通过网络支持扩展我的主应用程序(这是一个库)。我把网络服务放到一个额外的类中。

这里是我的网络支持创建的主应用程序/库的摘录:

QThread *thread = new QThread;
wifi = new WirelessNet(0, thread);
wifi->moveToThread(thread);
connect(thread,SIGNAL(started()), wifi,SLOT(initWifi()));
thread->start();

网络类扩展:

WirelessNet::WirelessNet(QObject *parent, QThread *comThread): QTcpServer(parent)

     clientThread = comThread;


void WirelessNet::initWifi()

    listen(QHostAddress::Any, 5220);
    connect(this,SIGNAL(newConnection()),this,SLOT(connectionRequest()));


void WirelessNet::connectionRequest()

    client = this->nextPendingConnection();
    if(client)
        connect(client, SIGNAL(readyRead()), this, SLOT(receiveMessage()));


void WirelessNet:sendData(QByteArray msg)

if (client)

    qDebug()<<"FIRST "<< client->thread() << " - " << this->thread() << "\n";
    client->write(msg);
    client->waitForBytesWritten();
    qDebug()<<"LAST " << client->thread() << " - " << this->thread() << "\n";


(client和clientThread分别是类成员:QTcpSocket*、QThread*)

调试

当涉及到sendData() 部分时,控制台会打印出以下内容:

FIRST QThread(0x7f66a0020be0) - QThread(0x7f66a0020be0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f66980022e0), parent's thread is QThread(0x7f66a0020be0), current thread is QThread(0x7f66a0020e20)
QSocketNotifier: Can only be used with threads started with QThread
LAST QThread(0x7f66a0020be0) - QThread(0x7f66a0020be0)

结论

换句话说,我不知道应该应用moveToThread() 哪个对象。我已经尝试过client-&gt;moveToThread(clientThread)this-&gt;moveToThread(clientThread)。不幸的是,我没有看到任何其他要检查的对象。

有人有想法吗?

【问题讨论】:

我不明白 clientThread 的设置方式/位置。您在构造函数中有clientThread = comThread;,但是当您创建WirelessNet 时,您为父级传入0,这很好,但您没有为线程传递第二个参数...:wifi= new WirelessNet(0);。为什么需要传入一个线程? - 您可以在 WirelessNet 中根据需要创建一个(可能将其作为成员变量),例如QThread *m_ClientThread 然后m_ClientThread = new QThread; 然后你有你的新线程和它全部封装在 WirelessNet 中(你可以使用 moveToThread...)。 @code_fodder 对不起,这是一个错字。我更新了顶帖(主应用程序)。我将线程传递给所需的父线程,以便将moveToThread() 传递给所需的父线程。问题是,所有(我知道的)都已经设置到父线程,但是我正在寻找的那个晦涩的对象 - 我希望它在帖子的 debugging 部分中很清楚。跨度> 你不会碰巧直接从主线程调用WirelessNet:sendData吧? 这个问题没有包含足够的代码来重现问题,因此是题外话。将来,当问此类问题时,请创建一个最小、自包含(单个main.cpp)的测试用例。参见例如this answer 以获取您问题中代码的外观示例。 这不是问题,正如 thuga 指出并回答的那样,您从另一个线程 +1 调用了一个函数方向,但只是想澄清另一件事。您将线程指针传递给它移动到的线程的 WirelessNet 并将其存储在 clientThread 中。你不需要,你可以用QThread::currentThread()访问你当前的线程——返回QThread *,但是你用这个QThread指针做什么呢? - 不知何故,它让我觉得其他事情可能是错的:o 【参考方案1】:

您似乎是直接从主线程调用WirelessNet:sendData。这会导致该函数内的所有内容也都在主线程中运行。您的 client 存在于新线程中,并且它不是线程安全的。它尝试创建子线程,但当前线程与 client 所在的线程不同。这就是您收到该错误消息的原因。

您可以简单地通过将WirelessNet:sendData 设置为插槽并通过来自主线程的信号调用它来修复它。

【讨论】:

【参考方案2】:

我的猜测是你的类的构造函数在调用线程中被调用,而线程本身在你的类的run()方法中运行。解决方案是在 run() 方法的开头初始化 QTcpServer,以便通过该类的初始化和通信在同一个线程中完成。

【讨论】:

我尝试了一个额外的QTcpServer* 成员,在initWifi() 中初始化并移动到clientThread,一切都设置到这个成员-服务器,扩展了qDebug () 与该服务器线程 - 现在与其他人一样 - 但错误是一致的 你可以用QThread::currentThread()检查代码的执行位置。我认为initWifi 再次被原始线程调用。我真的会尝试将它放在您的 run 方法的开头 我不确定您想到的是哪个run()WirelessNet 类继承自 QTcpServer,我没有实现 run(),也没有执行 wifi-&gt;start()。但是,由于第一次调用 initWifi,当 wifi 已经移动到新线程时,据我所知,不应再在旧线程中创建任何内容 好吧,忘了run。但是,您是否检查过哪个线程 initWifi 被调用?你是对的,它之前已经转移到新线程,但某种线程不匹配似乎仍然存在 感谢您的帮助,因为 thuga 表示我错过了发送的信号/插槽通信,我直接从 main 调用此函数。它现在正在工作

以上是关于无法使用 QtNetwork,因为应用程序使用不同的线程的主要内容,如果未能解决你的问题,请参考以下文章

C++ 非 QT 接口和 QtNetwork

Qt。如何使用 QtNetwork 查看网络上的其他计算机?

什么是 QtNetwork 相当于 shutdown(..., SHUT_WR)

如何在交叉编译 Windows 的 vlc 时包含 QtNetwork

在 BB10 应用程序开发的 cpp 文件中包含 <QtNetwork> 时出错

Python QtNetwork.QTcpSocket.readAll() 和 QtNetwork.QTcpSocket.write() 不起作用