Search code examples
qtsignals-slotsevent-loopqt-signals

Qt Signals and slots mechanism blocked by a loop in main


I have a following situatuion.

  • 2 Socket objects are created in the main in a for loop (the original problem has 1000 objects). Upon creation the start() method is invoked.
  • start() creates a QTcpSocket which tries to connect to some host.
  • Socket has slots which catch the connected() signal from QTcpSocket and print some debug output

What happens is that chronologically first ALL the Socket objects are created after which the sockets are started. Here is an example output of debug options:

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

Code:

//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.";
}

This is not the behavior I expected because the documentation states:

When a signal is emitted, the slots connected to it are usually executed immediately, just like a normal function call. When this happens, the signals and slots mechanism is totally independent of any GUI event loop.

Question:

How to ensure the slots are executed "immediately" (not only after the loop in the main finishes) when the signal is emitted?


The only available solution (without introducing new threads) i currently see:

Drop the use of signals and slots in this case, and implement everything in the start method. Something like this:

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

Solution

  • establishing the connection happens asynchronously (read connectToHost will return immediately before it even checks whether the connection has already been established) and will notify your code using the signals that are triggered by events

    these events are handled only in the event loop or when you call WaitForConnect (which will spin up it's own even loop only handling those events)

    this means that the sequence you get is perfectly normal