【问题标题】:Qt "no matching function for call to connect", modifying Qt Fortune Threaded Server exampleQt "no matching function for call to connect",修改Qt Fortune Threaded Server示例
【发布时间】:2013-09-27 02:25:18
【问题描述】:

我正在尝试修改 Qt Fortune Threaded Server 示例以从连接中读取文本,然后将其回显。我在我的 FortuneThread.h 文件中定义了 tcpSocket,如下所示:

QTcpSocket tcpSocket;

我的线程的新运行函数如下所示:

void FortuneThread::run()
{
    if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
        emit error(tcpSocket.error());
        return;
    }
    connect(&tcpSocket, SIGNAL(readyREAD()), this, SLOT(readCommand()) );
}

编译和运行,但是一旦我连接我得到这个错误(指连接线):

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x1eeb920), parent's thread is QThread(0x1bb3f90), current thread is FortuneThread(0x1eeb8f0)
QObject::connect: No such signal QTcpSocket::readyREAD() in ../fortune/fortunethread.cpp:60

有人可以向我解释原因吗?由于 tcpSocket 是在 FortuneThread 类(作为单独的线程运行)中定义的,并且“this”指的是 FortuneThread,我假设两个对象都在线程内?如何解决这个问题?

【问题讨论】:

    标签: multithreading qt qthread


    【解决方案1】:

    您的套接字对象已在主线程中创建,但您正在从不同的线程访问它。您需要在线程的run() 方法中创建它。定义套接字的位置无关紧要。它将在 C++ 运行时库进行静态对象初始化时从主线程创建。

    QTcpSocket * tcpSocket;
    
    ...
    
    void FortuneThread::run() {
      tcpSocket = new QTcpSocket;
      ...
    }
    

    【讨论】:

    • 好的,这是有道理的,崩溃消失了。但是,当我通过 telnet 连接发送文本时,永远不会调用 readCommand 函数(插槽)。还有什么明显的吗?如果没有,我将开始一个新的话题。谢谢
    • @Michelle:这里没有足够的代码来查看问题所在。您需要创建一个单文件、自包含的示例,该示例同时打开服务器和客户端连接(与其自身)。这可能足以让您了解问题所在。
    【解决方案2】:

    我同意Kuba Ober。您应该阅读关于 Qt 线程、对象和事件的 great guide。特别是称为跨线程的信号和槽部分。作者建议将控制器和工作部分拆分为不同的本质。

    代码中的第二个问题 - 区分大小写的信号名称。将其更改为readyRead

    【讨论】:

      【解决方案3】:

      Qt Fortune Threaded Server 示例的一个问题是它使用线程的方式。正如 Qt 的开发者所说,"You're doing it wrong"

      问题是QThread的继承。 QThread 类实际上不是线程,而是线程控制器类,继承它的唯一原因是如果你想改变控制线程的行为。

      您看到的问题是由于线程关联性造成的;对象属于哪个线程。

      如果一个线程是这样继承的:-

      class FortuneThread : public QThread
      {
          Q_OBJECT
      
          private:
              QTcpSocket tcpSocket;
      };
      

      然后从主线程实例化一个 FortuneThread 的对象:-

      FortuneThread* ft = new FortuneThread(parent);
      

      线程及其实例化的对象 (tcpSocket) 的线程亲和性现在是主线程,因此 tcpSocket 正在主线程上运行,这就是错误的说明。在调用 run 函数时,connect 来自 FortuneThread,但 tcpSocket 在主线程上。

      解决这个问题的更好方法是创建你的类,从 QObject 派生并将它移动到线程:-

      // Inherit from QObject, not QThread
      class FortuneSocket : public QObject
      {
          Q_OBJECT
      
          public slots:
             void Run();
          private:
              QTcpSocket tcpSocket;
      };
      
      
      QThread* pThread = new QThread(parent);
      FortuneSocket* pFortune = new FortuneSocket(parent);
      
      connect(pThread, &QThread::started, pFortune, &FortuneSocket::Run); // Qt5 connect style
      
      // move the fortune socket to the thread: -
      pFortune->moveToThread(pThread);
      

      现在,当您使用 pThread->start() 启动线程时,FortuneSocket 对象及其所有成员都在新线程上运行。

      以这种方式使用线程还意味着您可以将多个对象移动到单个线程,而不是每个线程拥有一个对象。请注意,创建多于 CPU 内核的线程是没有意义的!

      最后,还有一篇更深入的关于如何使用 QThread 的文章,here

      【讨论】:

        猜你喜欢
        • 2021-10-24
        • 1970-01-01
        • 2022-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-08
        • 2019-10-16
        • 2020-01-25
        相关资源
        最近更新 更多