Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

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

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 1.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • SPlattenS Offline
    SPlattenS Offline
    SPlatten
    wrote on last edited by SPlatten
    #1

    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);
            }
        }
    }
    

    Kind Regards,
    Sy

    KroMignonK 1 Reply Last reply
    0
    • SPlattenS SPlatten

      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);
              }
          }
      }
      
      KroMignonK Offline
      KroMignonK Offline
      KroMignon
      wrote on last edited by
      #2

      @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.

      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

      SPlattenS 1 Reply Last reply
      2
      • KroMignonK KroMignon

        @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.

        SPlattenS Offline
        SPlattenS Offline
        SPlatten
        wrote on last edited by SPlatten
        #3

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

        Fixed...

        Kind Regards,
        Sy

        KroMignonK 1 Reply Last reply
        0
        • SPlattenS SPlatten

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

          Fixed...

          KroMignonK Offline
          KroMignonK Offline
          KroMignon
          wrote on last edited by
          #4

          @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.

          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

          SPlattenS 1 Reply Last reply
          1
          • KroMignonK KroMignon

            @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.
            SPlattenS Offline
            SPlattenS Offline
            SPlatten
            wrote on last edited by SPlatten
            #5

            @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.

            Kind Regards,
            Sy

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved