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. QWaitCondition and Signals
Forum Updated to NodeBB v4.3 + New Features

QWaitCondition and Signals

Scheduled Pinned Locked Moved Unsolved General and Desktop
6 Posts 3 Posters 838 Views 2 Watching
  • 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.
  • S Offline
    S Offline
    stvokr
    wrote on last edited by stvokr
    #1

    Hi all,

    I have a problem with a QWaitCondition and Signals sent right before the thread is waiting.
    What can happen in the following situation? Is it possible that the signal is not sent immediately before the thread waits?
    Do I have to use Qt::BlockingQueuedConnection to setup the signal?

    // in class Device:
    
    ...
    LightControl* lc = Main->getLightControl();
    
    // the function checkLight() sends a request to a hardware component, the response arrives asynchronously.
    // the use of Qt::BlockingQueuedConnection should be possible here, as the hardware response is delayed.
    connect(this, &Device::setLightEnabled, lc, &LightControl::checkLight);
    emit setLightEnabled();
    
    m_mutex.lock();
    Main->getWaitCondition()->wait(&m_mutex);
    m_mutex.unlock();
    ...
    
    // in class Main, this function is called when the lightControl receives the response from the hardware.
    
    function wakeDevices()
    {
        m_waitCondition->wakeAll();
    }
    

    Everything seems to be fine on our test environment. But on other PCs the thread sometimes freezes.
    Any ideas?

    Regards
    Oliver

    JonBJ 1 Reply Last reply
    0
    • S stvokr

      Hi all,

      I have a problem with a QWaitCondition and Signals sent right before the thread is waiting.
      What can happen in the following situation? Is it possible that the signal is not sent immediately before the thread waits?
      Do I have to use Qt::BlockingQueuedConnection to setup the signal?

      // in class Device:
      
      ...
      LightControl* lc = Main->getLightControl();
      
      // the function checkLight() sends a request to a hardware component, the response arrives asynchronously.
      // the use of Qt::BlockingQueuedConnection should be possible here, as the hardware response is delayed.
      connect(this, &Device::setLightEnabled, lc, &LightControl::checkLight);
      emit setLightEnabled();
      
      m_mutex.lock();
      Main->getWaitCondition()->wait(&m_mutex);
      m_mutex.unlock();
      ...
      
      // in class Main, this function is called when the lightControl receives the response from the hardware.
      
      function wakeDevices()
      {
          m_waitCondition->wakeAll();
      }
      

      Everything seems to be fine on our test environment. But on other PCs the thread sometimes freezes.
      Any ideas?

      Regards
      Oliver

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @stvokr
      So far as I know, the signal will be emitted as soon as the emit setLightEnabled() is executed (I don't think that has to wait until the thread's event loop is entered, but I stand to be corrected by an expert if that is not the case?). Since the connection is across threads that will queue the signal/slot to be called in the slot thread. And that will execute the next time that thread gets to process its event loop.

      Your caller does a Main->getWaitCondition()->wait(&m_mutex); and your receiver does a m_waitCondition->wakeAll();. You might assume that the caller will reach >wakeAll() before the recipient reaches wait(&m_mutex), and this might the case "many times", but there is no guarantee they will not happen in the opposite order, depending on thread scheduling. If that happens the wakeAll() will have executed before the wait(). Test that case: doesn't that mean the wakeAll() will have "wasted"/"lost" and then the wake() will just hang/freeze?

      Qt::BlockingQueuedConnection will doubtless handle this situation better than your code. But it still has its own issues. I don't know whether it will be preferable. Something like https://woboq.com/blog/how-qt-signals-slots-work-part3-queuedconnection.html gives some details on this.

      Another approach you might consider is not to block waiting for a signal to be delivered and a "response" (here wakeAll()) but instead have the receiver issue its own (non-blocking) signal when it has processed the original signal. And your thread puts a slot on that and does its "continuation" code there rather than in the original code right after emit setLightEnabled();. Depends what that code is needing to do.

      S 1 Reply Last reply
      0
      • JonBJ JonB

        @stvokr
        So far as I know, the signal will be emitted as soon as the emit setLightEnabled() is executed (I don't think that has to wait until the thread's event loop is entered, but I stand to be corrected by an expert if that is not the case?). Since the connection is across threads that will queue the signal/slot to be called in the slot thread. And that will execute the next time that thread gets to process its event loop.

        Your caller does a Main->getWaitCondition()->wait(&m_mutex); and your receiver does a m_waitCondition->wakeAll();. You might assume that the caller will reach >wakeAll() before the recipient reaches wait(&m_mutex), and this might the case "many times", but there is no guarantee they will not happen in the opposite order, depending on thread scheduling. If that happens the wakeAll() will have executed before the wait(). Test that case: doesn't that mean the wakeAll() will have "wasted"/"lost" and then the wake() will just hang/freeze?

        Qt::BlockingQueuedConnection will doubtless handle this situation better than your code. But it still has its own issues. I don't know whether it will be preferable. Something like https://woboq.com/blog/how-qt-signals-slots-work-part3-queuedconnection.html gives some details on this.

        Another approach you might consider is not to block waiting for a signal to be delivered and a "response" (here wakeAll()) but instead have the receiver issue its own (non-blocking) signal when it has processed the original signal. And your thread puts a slot on that and does its "continuation" code there rather than in the original code right after emit setLightEnabled();. Depends what that code is needing to do.

        S Offline
        S Offline
        stvokr
        wrote on last edited by
        #3

        @JonB
        Yes, I also found out that the wake() could be called earlier than wait(). That's why I'm thinking about the Qt::BlockingQueuedConnection.
        And the other approach is not possible because the device thread is in a state machine that cannot be interrupted at this point.

        I will test the blocking connection.
        Thanks.

        JonBJ 1 Reply Last reply
        0
        • S stvokr

          @JonB
          Yes, I also found out that the wake() could be called earlier than wait(). That's why I'm thinking about the Qt::BlockingQueuedConnection.
          And the other approach is not possible because the device thread is in a state machine that cannot be interrupted at this point.

          I will test the blocking connection.
          Thanks.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @stvokr said in QWaitCondition and Signals:

          Yes, I also found out that the wake() could be called earlier than wait().

          This is only guesswork/intuition, but maybe this is the correct order:

          m_mutex.lock();
          emit setLightEnabled();
          Main->getWaitCondition()->wait(&m_mutex);
          m_mutex.unlock();
          
          void wakeDevices()
          {
              m_mutex.lock();
              m_waitCondition->wakeAll();
              m_mutex.unlock();
          }
          

          [Your problem sorting out the sharing/visibility of m_mutex from secondary thread to main thread.]
          My intention here, if it works, is to pre-lock the mutex before the emit to make it so the wakeAll() is not executed until the wait() releases the mutex lock, so it cannot be "missed".

          SGaistS 1 Reply Last reply
          0
          • JonBJ JonB

            @stvokr said in QWaitCondition and Signals:

            Yes, I also found out that the wake() could be called earlier than wait().

            This is only guesswork/intuition, but maybe this is the correct order:

            m_mutex.lock();
            emit setLightEnabled();
            Main->getWaitCondition()->wait(&m_mutex);
            m_mutex.unlock();
            
            void wakeDevices()
            {
                m_mutex.lock();
                m_waitCondition->wakeAll();
                m_mutex.unlock();
            }
            

            [Your problem sorting out the sharing/visibility of m_mutex from secondary thread to main thread.]
            My intention here, if it works, is to pre-lock the mutex before the emit to make it so the wakeAll() is not executed until the wait() releases the mutex lock, so it cannot be "missed".

            SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #5

            Hi,

            From old memory, locking a mutex and emitting a signal afterward is a recipe for issues.

            @stvokr can you explain why you would need a QWaitCondition ? The fact that your hardware sends an answer asynchronously sounds like it should be simpler to integrate with Qt. Send your request and when you get the answer, emit a signal at that point so you don't need any mutex or wait condition.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            S 1 Reply Last reply
            0
            • SGaistS SGaist

              Hi,

              From old memory, locking a mutex and emitting a signal afterward is a recipe for issues.

              @stvokr can you explain why you would need a QWaitCondition ? The fact that your hardware sends an answer asynchronously sounds like it should be simpler to integrate with Qt. Send your request and when you get the answer, emit a signal at that point so you don't need any mutex or wait condition.

              S Offline
              S Offline
              stvokr
              wrote on last edited by
              #6

              @SGaist Hi, this isn't so easy to explain.
              I can even have several device threads that are to interact with the hardware, whereby only the first thread sends the request to the hardware.
              The other requests are skipped. The hardware sends the response asynchronously, so I have to wait for it.
              During this time, the other threads have to wait in the function they are currently in. They cannot leave the scope in between.

              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