【问题标题】:QT: socket notifiers cannot be enabled from another threadQT:无法从另一个线程启用套接字通知器
【发布时间】:2025-12-16 12:00:02
【问题描述】:

我有一个 QTcpSocket,我需要控制它 - 使用多个线程进行写入 + 读取。

这在 QT4 中运行良好,但在 QT5 中出现此错误,似乎只有 1 个线程可以同时访问套接字。如何让一个套接字可以被多个线程访问?

基本上我想创建 1 个用于读取数据的线程和 1 个用于写入数据的线程,这样我就可以在应用程序的其余部分执行其他操作时异步读取和处理数据。

注意:Qt - Handle QTcpSocket in a new thread 的回答在这里没有帮助,因为它描述了如何将套接字从线程 1 传输到线程 2,然后仅从线程 2 使用它。我需要从两个线程中使用它。

【问题讨论】:

  • 为什么不能通过信号和槽向托管 QTcpSocket 实例的线程发送消息?当您声明“我收到此错误”时,将错误添加到问题中会很有帮助。
  • 嗯,一读一写线程应该没问题。一个以上的接收将成为问题,因为 TCP 字节流不能发送超过一个字节的消息 - 任何 rx 线程都可能进入并且仅 rx 部分缓冲区。我会说@Merlin069 对此有解决方案 - 将请求/响应对象排队到一个线程。
  • 您可以使用跨线程信号/插槽来发送读取数据/要写入的数据。我仍然想知道共享单个套接字的用例是什么,我希望它需要更高级别的同步(正如 Martin 建议的那样)才能有任何用途。
  • @Merlin069 “这个错误”是主题错误(无法从另一个线程启用套接字通知器)
  • @MartinJames 是的 - 这就是我想要完成的 - 一个用于写作,1 个用于阅读,但显然我无法为此创建任何线程

标签: c++ multithreading qt sockets


【解决方案1】:

您只能从一个线程直接与套接字交互(该线程必须运行一个事件循环 - 所以您应该在其上调用exec())。如果你想从另一个线程读/写,你需要使用 Signals/Slots。

使用默认连接类型 (Qt::AutoConnection) 将一个线程上发出的信号连接到另一个线程上的对象的 Slot 将自动确保发生安全的线程传输(使用排队连接)。您可以使用Qt::QueuedConection 将信号显式连接到插槽,但Qt::AutoConnection 应该可以正常工作。

// Lives on thread 1
class MySocketOwner : public QObject
{
    Q_OBJECT

public:
    MySocketOwner(QObject *Parent = 0)
        : QObject(Parent)
    {
        Socket = new QTcpSocket(this);
        connect(Socket, SIGNAL(readyRead()), this, SLOT(Read()));
    }

    ~MySocketOwner()
    {
        delete Socket;
    }

public slots:
    void Read()
    {
        QByteArray Data = Socket->readAll();
        // Do something with the data
    }

    void Write(QBytrArray Data)
    {
        // Must always be called on thread 1
        Socket->write(Data);
    }

private:
    QTcpSocket *Socket;
};

// Lives on thread 2
class MySocketWriter : public QObject
{
    Q_OBJECT

public:
    MySocketWriter(QObject *Parent = 0)
        : QObject(Parent)
    {
        // If this is on another thread, connection will be queued
        connect(this, SIGNAL(Write(QByteArray)), MySocketOwnerPointer, SLOT(Write(QBytrArray Data)));
        QByteArray Data;
        // Fill with data

        // An event gets put onto thread 1's event queue after this
        emit Write(Data);
    }

signals:
    void Write(QByteArray Data);
};

就像您问题中的 cmets 所说,您需要仔细考虑为什么需要这种行为,您真的需要在 2 个单独的线程上读取套接字接收到的相同数据吗?

【讨论】:

  • 我不需要在 2 个线程上读取数据。我想在 1 个线程中阅读它们并在另一个线程中写入