Qt“没有用于连接呼叫的匹配功能”,修改了Qt Fortune Threaded Server示例

时间:2013-09-27 02:25:18

标签: multithreading qt qthread

我正在尝试修改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类中定义的(它作为一个单独的线程运行),并且"这个"是指FortuneThread,我假设这两个对象都在线程内?如何解决这个问题?

3 个答案:

答案 0 :(得分:4)

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

QTcpSocket * tcpSocket;

...

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

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

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的更深入的文章。