如何在不同的线程中执行QTcpSocket?

时间:2010-04-23 11:35:48

标签: c++ multithreading qt tcp qt4

如何在不同的线程中执行QTcpSocket函数?

5 个答案:

答案 0 :(得分:6)

QT文档明确指出QTCPSocket不应该在线程中使用。 I.E,在主线程中创建一个QTCPSocket,并将信号绑定到另一个线程中的对象。

我怀疑你正在实现类似于web服务器的东西,其中listen在accept上创建了一个QTCPSocket。然后,您需要另一个线程来处理处理该套接字的任务。你不能。

我解决这个问题的方法是将套接字保留在它所生成的线程中。我为该线程中的所有传入数据提供服务并将其放入队列中,其他线程可以处理该数据。

答案 1 :(得分:5)

请务必注意在线程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;
});

其中m_thread是某个成员线程(基本上只是确保其生存期大于当前立即作用域),而m_concurrentQueue是某个线程安全队列或std容器具有互斥保护。

您还需要将一些信号(通常称为joinAll)连接到事件循环退出函数,并从类析构函数中进行调用。当使用线程中的事件循环习惯时,您始终必须注意确保可以正确地销毁该类,否则您的程序将不会退出(或在Windows上通常会被某些析构函数终止)不会被调用,并且最终会变成一个无提示错误)。

我通常也使用条件变量在创建线程之后等待事件循环开始。不必要,但是如果将这些线程放到构造函数中,则可以帮助使程序流程更有意义。

答案 2 :(得分:1)

围绕所有调用设置QMutex锁定,而不仅仅是在“不同”线程上,而是在所有线程上。一种简单的方法是通过QMutexLocker

答案 3 :(得分:1)

我在文档中读到的是QTcpSocket不应跨线程使用。如果你想在另一个线程中使用它,Qt docs说你应该在线程中创建一个新的QTcpSocket实例,并在新实例上设置描述符。为此,您需要重新实现QTcpServer并使用QTcpServer::incomingConnection。提供了一个简单示例here

答案 4 :(得分:-4)

以下是示例:

file thread.h:

class   Thread : public QThread {
    Q_OBJECT
public:
    Thread();
protected:
    void    run();
}

file thread.cpp:

Thread::Thread() {}
void    Thread::run() {
    // do what ever you want with QTcpSocket
}

在main.cpp或其他:

Thread *myThread = new Thread;
connect(myThread, SIGNAL(finished()), this, SLOT(on_myThread_finished()));
myThread->start();