小智 6
QT文档明确指出QTCPSocket不应该在线程中使用.IE,在主线程中创建一个QTCPSocket,并将信号绑定到另一个线程中的对象.
我怀疑你正在实现类似于web服务器的东西,其中listen在accept上创建了一个QTCPSocket.然后,您需要另一个线程来处理处理该套接字的任务.你不能.
我解决这个问题的方法是将套接字保留在它生成的线程中.我为该线程中的所有传入数据提供服务并将其放入一个队列,其中另一个线程可以处理该数据.
重要的是要注意在线程方面您可以做什么和不能做什么QTcpSocket
:
您可以在非主线程中使用它,但只能在创建它的线程中使用。
您不能QTcpSocket
从不同的线程调用不同的函数,例如在一个线程中读取,在另一个线程中写入。相反,您可以为每个 制作一个单独的线程QTcpSocket
,这样可以防止它们占用可能在主线程中绘制小部件的时间和资源。
IMO,将您的 IO,包括QTcpSocket
在主线程以外的线程中,是任何高性能应用程序的最佳实践和必须做的事情。我一直使用QTcpSocket
以下习语在非主线程中使用:
// Read data from a QTcpSocket in a thread. Assumes this is in some class.
m_thread = std::thread([this]
{
QEventLoop eventLoop;
QTcpSocket* socket = new QTcpSocket(&eventLoop);
socket->connectToHost("localhost", 9999);
// enqueue or process the data
QObject::connect(socket, &QTcpSocket::readyRead, &eventLoop, [socket]
{
m_concurrentQueue.push_back(socket->readAll());
});
// Quit the loop (and thread) if the socket it disconnected. You could also try
// reconnecting
QObject::connect(socket, &QTcpSocket::disconnected, &eventLoop, [&eventLoop]
{
eventLoop.quit();
});
eventLoop.exec();
delete socket;
});
Run Code Online (Sandbox Code Playgroud)
哪里m_thread
是某个成员线程(基本上只是确保它的生命周期大于当前的直接范围),并且m_concurrentQueue
是某个线程安全队列或std
具有互斥保护的容器。
您还需要将一些信号(我通常称之为joinAll
)连接到事件循环退出函数,并从类析构函数中调用它。当使用一个线程中的事件循环习语时,你总是要小心确保你可以正确地销毁类,否则你的程序不会退出(或者在 Windows 上它会被终止,通常带有一些析构函数没有被调用,它最终是一个无声的错误)。
我通常还使用条件变量在创建线程后等待事件循环开始。这不是必需的,但如果您将这些线程放在构造函数中,它可以帮助使程序流程更有意义。