Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread



  • I have two processes A and B, A is listening to QHostAddress::Any and port 8123, B is listening QHostAddress::Any and port 8124.

    A starts B and B sends a message to A when its ready for use. It then sends a regular heartbeat message to A to let it know that its alive, A sends back an acknowledge for each heartbeat to let B know that A is still alive.

    When A is started it has a few messages for B but B hasn't been launched yet or is not ready so these messages are queued until B is ready.

    When A is notified that B is ready it connects to the port that B is listening to 8124. A then creates a timer to schedule sending queued messages to B.

    The problem is that the socket created by A when B is ready results in the following message when any attempt is made to write data to the socket:

    QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
    

    Here is the body of the timer:

    void clsModule::sendQueued() {
        mmpList::iterator itrQueue = clsModule::msmpSendLater.find(mstrAlias);
    
        if ( itrQueue == clsModule::msmpSendLater.end() ) {
        //No list for this module found!
            return;
        }
        lstJSON* plstMsgs = itrQueue->second;
    
        if ( plstMsgs == nullptr ) {
            return;
        }
        if ( plstMsgs->size() > 0 ) {
            QJsonObject objJSON = plstMsgs->takeFirst();
    
            if ( objJSON.isEmpty() == true ) {
                return;
            }
            QByteArray arybytMsg(QJsonDocument(objJSON).toJson(QJsonDocument::Compact));
            mpsckSender->write(arybytMsg);
            mpsckSender->flush();
        }
        if ( plstMsgs->size() == 0 ) {
            mptmrSendQueued->stop();
            delete mptmrSendQueued;
            mptmrSendQueued = nullptr;
        }
    }
    

    The socket mpsckSender is created in the main thread with:

    void clsModule::connectToModule(quint16 uint16Port) {
        Q_ASSERT_X(mpsckSender==nullptr, "clsModule::connectToModule"
                                         , "Sender already set!");
        if ( uint16Port > 0 ) {
            mpsckSender = new QTcpSocket();
            mpsckSender->setSocketOption(QAbstractSocket::LowDelayOption, 1);
            QObject::connect(mpsckSender, &QAbstractSocket::connected
                            ,this, &clsModule::onConnectedToModule);
            QObject::connect(mpsckSender, &QAbstractSocket::disconnected
                            ,this, &clsModule::onDisconnFromModule);
            QObject::connect(mpsckSender, &QAbstractSocket::readyRead
                            ,this, &clsModule::onReadFromModule);
            QAbstractSocket::SocketState eState = mpsckSender->state();
    
            if ( eState != QAbstractSocket::HostLookupState
              && eState != QAbstractSocket::ConnectedState
              && eState != QAbstractSocket::ConnectingState ) {
                mpsckSender->connectToHost(QHostInfo::localHostName(), uint16Port);
            }
        }
    }
    


  • @SPlatten said in QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread:

    QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    This is simple: you are using the QTcpSocket instance from another thread as the hosting thread: in short socket->thread() != QThread::currentThread() when calling socket->write().
    A QTcpSocket instance, like many Qt classes, must be used in his working thread.



  • @SPlatten said in QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread:

    QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    This is simple: you are using the QTcpSocket instance from another thread as the hosting thread: in short socket->thread() != QThread::currentThread() when calling socket->write().
    A QTcpSocket instance, like many Qt classes, must be used in his working thread.



  • @KroMignon , ok is there a way to satisfy this without having to connect on each iteration of the timer?

    Fixed...



  • @SPlatten said in QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread:

    ok is there a way to satisfy this without having to connect on each iteration of the timer?

    Yes, they are 2 solutions:

    • do not use different threads. Are you really sure the extra thread for the QTcpSocket is required? QTcpSocket already works asynchronously, so if you don't have to handle big traffic or long calculation there is no need of an extra thread.
    • change QTimer connection to use the socket instance as receiver.


  • @KroMignon , thank you, the purpose of the thread is that I intend to write X number of additional modules so there will be one main engine and any number of modules which could be sending messages to the engine. The engine will accept the messages and put them into a queue which the engine will use a thread will process so it isn't hung up on anything.


Log in to reply