我正在尝试修改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,我假设这两个对象都在线程内?如何解决这个问题?
答案 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的更深入的文章。