【问题标题】:Qt Signals and slots mechanism blocked by a loop in mainQt 信号和槽机制被 main 中的循环阻塞
【发布时间】:2013-10-25 08:24:36
【问题描述】:

我有以下情况。

  • 2 Socket 对象在 for 循环中的 main 中创建(原始问题有 1000 个对象)。创建时会调用 start() 方法。
  • start() 创建一个 QTcpSocket 尝试连接到某个主机。
  • Socket 具有从 QTcpSocket 捕获 connected() 信号并打印一些调试输出的插槽

按时间顺序首先创建所有Socket 对象,然后启动套接字。这是调试选项的示例输出:

1. Created Socket object 1
2. Invoked Socket object 1 start()
3. Created Socket object 2
4. Invoked Socket object 2 start()
5. Socket object 1 TcpSocket Connected
6. Socket object 2 TcpSocket Connected

代码:

//main.cpp
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    for (int i=0; i<10; i++)
    {
        Socket *socket = new Socket();
        qDebug() << "Socket object created";
        socket->Start();
    }
    return a.exec();
}

//socket.cpp
Socket::Socket(QObject *parent)
    : QObject(parent)
{}

void Socket::Start()
{
    qDebug()<<"Start method invoked";
    socket = new QTcpSocket(this);

    connect(socket,SIGNAL(connected()), this, SLOT(on_connect()), Qt::DirectConnection);
    socket->connectToHost("192.168.5.5",12345);
}

void Socket::on_connect()
{
    QTcpSocket* socket = qobject_cast<QTcpSocket *>(QObject::sender());
    qDebug() << socket->socketDescriptor() <<  " Connected.";
}

这不是我所期望的行为,因为documentation 声明:

当一个信号发出时,连接到它的槽通常是 立即执行,就像正常的函数调用一样。当这 发生时,信号和槽机制完全独立于任何 GUI 事件循环。

问题

当信号发出时,如何确保插槽“立即”执行(不仅在主循环完成后)?


我目前看到的唯一可用的解决方案(不引入新线程)

在这种情况下放弃使用信号和插槽,并在start 方法中实现所有内容。像这样的:

Socket::start(){
...
if(!tcpsocket->waitForConnected(200)) qDebug() << "Socket object X TcpSocket Connected"
...
}

【问题讨论】:

  • 你能多写一点代码吗?
  • 如果你给出一个代码示例而不是描述它会更有用。我可以用多种方式解释您的描述,但会确切地知道源代码在做什么。
  • @Merlin069 已更新代码
  • slots 在信号发出后立即执行(当使用 directConnection 或来自一个线程的对象通过 AutomaticConnection(默认值)连接时)。现在您可能不高兴,因为您期望 Socket object 1 TcpSocket Connected 应该在位置 3 而不是 5。这里的问题是 SIGNAL 在正确建立连接后发出,并且需要事件循环来接收一些系统通知。

标签: qt signals-slots event-loop qt-signals


【解决方案1】:

QTcpSocket 的信号connected() 发出时,您的插槽确实会立即触发。

但是,connected() 不会在您尝试将该套接字连接到某个地方时发出。

文档写道:

在调用 connectToHost() 后发出此信号 并且已成功建立连接。

连接的建立需要一个事件循环。

【讨论】:

    【解决方案2】:

    建立连接是异步发生的(读取connectToHost 将在它甚至检查连接是否已经建立之前立即返回)并将使用事件触发的信号通知您的代码

    这些事件仅在事件循环中或当您调用 WaitForConnect 时处理(这将启动它自己的偶数循环仅处理这些事件)

    这意味着你得到的序列是完全正常的

    【讨论】:

    • 信号和事件没有堆叠在同一个队列中?
    • 它们是,但您似乎对套接字的同步性感到困惑
    • 你说these events are handled only in the event loop。这是否意味着 main 中的“for循环”阻塞了事件/信号队列的填充?而且由于队列中没有信号,所以不会触发插槽?
    • 仍然可以填充队列,但连接事件仅在循环中处理,然后将它们推送到队列中
    【解决方案3】:

    如果不引入新线程,我认为您无法做到这一点,唯一的解决方案似乎是您的解决方案。

    或者使用 DirectConnection 而不是将其留空(在您的情况下是 AutomaticConnection 和 QueuedConnection)可能是一种解决方案。但我认为它不会起作用,因为您需要等待才能运行该插槽。我不确定,试试看吧。

    【讨论】:

    • 我手动设置为Qt::DirectConnection,没有用。我相信情况就是这样,因为所有内容都在同一个线程中,所以Qt::AutoConnectionQt::DirectConnection 相同。
    • 那你做不到,下一个答案解释了为什么你做不到。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多