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. QTimer doesn't stop on calling stop()

QTimer doesn't stop on calling stop()

Scheduled Pinned Locked Moved Unsolved General and Desktop
qtimercrash
11 Posts 4 Posters 2.0k 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.
  • S schrute

    I am using a QTimer to scan a QVector of probes every second and remove any probes that have expired. After a certain point, I need to stop the timer but I keep on receiving timeout events even after calling stop() on the QTimer object, which eventually leads to a crash.

    class MyObject : public QObject {
        Q_OBJECT
    
        QVector<Probe>  m_pending;
        QList<Probe>  m_done;
        QTimer m_timer;
    public:
        MyObject(QObject* p): QObject(p)
        {
            connect(&m_timerr, &QTimer::timeout, this, &MyObject::timeoutFired, Qt::DirectConnection);
            m_timer.setInterval(1000);
            m_timer.start();
        }
    
        void timeoutFired()
        {
            qDebug() << "[timeout] timeoutFired";
    
            if (!m_timer.isActive())
                return;
    
            auto pivot = std::partition(m_pending.begin(),
                                        m_pending.end(),
                                        [this](const Probe& probe) {
                                            return !probe.expired;
                                        });
    
            for (auto it = pivot; it != m_pending.end(); ++it) {
                process(*it);
            }
    
            m_pending.resize(std::distance(m_pending.begin(), pivot));
        }
    
        void someFunction() 
        {
            ...
            m_timer.stop();
            ...
        }
    }
    

    Following is the stack tracing of the crashing process

    * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
        frame #0: 0x00007ff805146c58 libc++abi.dylib`__cxa_throw
      * frame #1: 0x000000010c7969fc QtCore`qBadAlloc() at qglobal.cpp:3356:5 [opt]
        frame #2: 0x000000010c7e60d5 QtCore`QListData::detach_grow(this=0x00007f9f9a41a450, idx=0x000000030597af54, num=<unavailable>) at qlist.cpp:97:5 [opt]
        frame #3: 0x0000000100c05c73 MyProgram`QList<Probe>::detach_helper_grow(this=0x00007f9f9a41a450, i=2147483647, c=1) at qlist.h:803:28
        frame #4: 0x0000000100bf1ed0 MyProgram`QList<Probe>::append(this=0x00007f9f9a41a450, t=0x000000030597b0e0) at qlist.h:623:19
        frame #5: 0x0000000100bf22e4 MyProgram`MyObject::process(this=0x00007f9f9a005950, Probe=0x00000001239999e) at MyProgram.cpp:2216:5
        frame #6: 0x0000000100bf01b5 MyProgram`MyObject::timeoutFired(this=0x00007f9f9a005950) at MyProgram.cpp:2283:9
        frame #7: 0x0000000100c04b4b MyProgram`QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (MyObject::*)()>::call(f=50 ff be 00 01 00 00 00 00 00 00 00 00 00 00 00, o=0x00007f9f9a005950, arg=0x000000030597b390)(), MyObject*, void**) at qobjectdefs_impl.h:152:13
        frame #8: 0x0000000100c04a8d MyProgram`void QtPrivate::FunctionPointer<void (MyObject::*)()>::call<QtPrivate::List<>, void>(f=50 ff be 00 01 00 00 00 00 00 00 00 00 00 00 00, o=0x00007f9f9a005950, arg=0x000000030597b390)(), MyObject*, void**) at qobjectdefs_impl.h:185:13
        frame #9: 0x0000000100c04982 MyProgram`QtPrivate::QSlotObject<void (MyObject::*)(), QtPrivate::List<>, void>::impl(which=1, this_=0x00006000034ff200, r=0x00007f9f9a005950, a=0x000000030597b390, ret=0x0000000000000000) at qobjectdefs_impl.h:418:17
        frame #10: 0x000000010c9afe85 QtCore`void doActivate<false>(QObject*, int, void**) [inlined] QtPrivate::QSlotObjectBase::call(this=<unavailable>, r=<unavailable>, a=0x000000030597b390) at qobjectdefs_impl.h:398:51 [opt]
        frame #11: 0x000000010c9afe70 QtCore`void doActivate<false>(sender=0x00007f9f9a005a58, signal_index=3, argv=0x000000030597b390) at qobject.cpp:3923 [opt]
        frame #12: 0x000000010c9b94f2 QtCore`QTimer::timerEvent(QTimerEvent*) [inlined] QTimer::timeout(_t1=QPrivateSignal @ 0x000000030597b388) at moc_qtimer.cpp:205:5 [opt]
        frame #13: 0x000000010c9b94cd QtCore`QTimer::timerEvent(this=0x00007f9f9a005a58, e=<unavailable>) at qtimer.cpp:257 [opt]
        frame #14: 0x000000010c9a76ef QtCore`QObject::event(this=0x00007f9f9a005a58, e=0x000000030597b720) at qobject.cpp:1324:9 [opt]
        frame #15: 0x0000000109bf0afa QtWidgets`QApplicationPrivate::notify_helper(this=<unavailable>, receiver=0x00007f9f9a005a58, e=0x000000030597b720) at qapplication.cpp:3640:26 [opt]
        frame #16: 0x0000000109bf1f21 QtWidgets`QApplication::notify(this=<unavailable>, receiver=0x00007f9f9a005a58, e=0x000000030597b720) at qapplication.cpp:0:9 [opt]
        frame #17: 0x000000010c97c304 QtCore`QCoreApplication::notifyInternal2(receiver=0x00007f9f9a005a58, event=0x000000030597b720) at qcoreapplication.cpp:1064:18 [opt]
        frame #18: 0x000000010c9e1f5f QtCore`QTimerInfoList::activateTimers(this=<unavailable>) at qtimerinfo_unix.cpp:643:13 [opt]
        frame #19: 0x000000010acc6cd2 libqcocoa.dylib`QCocoaEventDispatcherPrivate::activateTimersSourceCallback(void*) [inlined] QCocoaEventDispatcherPrivate::processTimers(this=0x00007f9f9a10a850) at qcocoaeventdispatcher.mm:131:35 [opt]
        frame #20: 0x000000010acc6cc9 libqcocoa.dylib`QCocoaEventDispatcherPrivate::activateTimersSourceCallback(info=0x00007f9f9a10a850) at qcocoaeventdispatcher.mm:125 [opt]
    

    As per the stack trace, it is crashing in the process method that gets called from the timeoutFired method. Another weird thing is that I am printing a log in the first line of timeoutFired but it doesn't get printed when the app crashes. The program is compiled with -O0.

    Any idea what could be happening here? I am not sure if the backtrace makes sense, but I am able to reproduce the issue 100% of the time and it always has the same backtrace.

    Christian EhrlicherC Offline
    Christian EhrlicherC Offline
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on last edited by
    #2

    First please post the actual code which really runs - your code above does not compile at all. Then please minimize your code so we can run it also. Since it's crashing in process() - what does this function do?

    When you call stop() then the timer stops - except you call it from another thread then you will get a runtime warning.

    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
    Visit the Qt Academy at https://academy.qt.io/catalog

    S M 2 Replies Last reply
    1
    • Christian EhrlicherC Christian Ehrlicher

      First please post the actual code which really runs - your code above does not compile at all. Then please minimize your code so we can run it also. Since it's crashing in process() - what does this function do?

      When you call stop() then the timer stops - except you call it from another thread then you will get a runtime warning.

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

      @Christian-Ehrlicher This is actually part of a larger program. Let me see if I can strip it, but I am not too sure if the problem is with the timer or I am getting an incorrect stack trace. The process method copies Probes that have timed out to a QList. The problem is that even if timeoutFired gets called, m_pending is empty at that point and all that code should have been skipped including the for-loop. If I add logs in the timeoutFired method then they don't get printed in the invocation where it crashes which makes me doubtful that it was called.

      Also, the program is single-threaded.

      1 Reply Last reply
      0
      • Christian EhrlicherC Christian Ehrlicher

        First please post the actual code which really runs - your code above does not compile at all. Then please minimize your code so we can run it also. Since it's crashing in process() - what does this function do?

        When you call stop() then the timer stops - except you call it from another thread then you will get a runtime warning.

        M Offline
        M Offline
        mpergand
        wrote on last edited by
        #4

        I experienced that the (last) pending event can be fired despite the timer is stopped !

        Christian EhrlicherC 1 Reply Last reply
        0
        • M mpergand

          I experienced that the (last) pending event can be fired despite the timer is stopped !

          Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #5

          @mpergand said in QTimer doesn't stop on calling stop():

          I experienced that the (last) pending event can be fired despite the timer is stopped !

          Only when the event is already in the event queue.

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          M S 2 Replies Last reply
          1
          • Christian EhrlicherC Christian Ehrlicher

            @mpergand said in QTimer doesn't stop on calling stop():

            I experienced that the (last) pending event can be fired despite the timer is stopped !

            Only when the event is already in the event queue.

            M Offline
            M Offline
            mpergand
            wrote on last edited by
            #6

            @Christian-Ehrlicher said in QTimer doesn't stop on calling stop():

            Only when the event is already in the event queue.

            Correct, could be problematic.

            1 Reply Last reply
            0
            • Christian EhrlicherC Christian Ehrlicher

              @mpergand said in QTimer doesn't stop on calling stop():

              I experienced that the (last) pending event can be fired despite the timer is stopped !

              Only when the event is already in the event queue.

              S Offline
              S Offline
              schrute
              wrote on last edited by
              #7

              @Christian-Ehrlicher Is this possible with a direct connection? Even then it doesn't explain why the logs are not getting printed. I also tried setting a debugger breakpoint but it is also not working for the invocation where it crashes.

              Christian EhrlicherC M 2 Replies Last reply
              0
              • S schrute

                @Christian-Ehrlicher Is this possible with a direct connection? Even then it doesn't explain why the logs are not getting printed. I also tried setting a debugger breakpoint but it is also not working for the invocation where it crashes.

                Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #8

                @schrute said in QTimer doesn't stop on calling stop():

                Is this possible with a direct connection?

                I don't see what this has to do with the connection. We were talking about the fact that you call stop() within a slot while in the Qt event queue the timer event is already added. Then the slot might get called but I'm unsure about it. You have to read the source code wrt this to be really sure. But I doubt this is your problem.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                1 Reply Last reply
                0
                • S schrute

                  @Christian-Ehrlicher Is this possible with a direct connection? Even then it doesn't explain why the logs are not getting printed. I also tried setting a debugger breakpoint but it is also not working for the invocation where it crashes.

                  M Offline
                  M Offline
                  mpergand
                  wrote on last edited by
                  #9

                  @schrute
                  Try to explicitly disconnect your slot from the timer when you stop it.

                  Axel SpoerlA 1 Reply Last reply
                  0
                  • M mpergand

                    @schrute
                    Try to explicitly disconnect your slot from the timer when you stop it.

                    Axel SpoerlA Offline
                    Axel SpoerlA Offline
                    Axel Spoerl
                    Moderators
                    wrote on last edited by
                    #10

                    @schrute
                    As @Christian-Ehrlicher said, QTimer::timeout can be posted before and delivered after the timer was stopped.
                    QTimer::stop()removes the timer synchronously, which means no more signals are emitted from that moment.
                    Disconnecting a driver when no longer used, is never a bad idea. That could be implemented in a small function stopTimer(). However, it does not prevent previously emitted signals from being delivered.
                    The active property should normally be synchronous, but I am not sure if it can leak a bit behind (it's a computed property and not a simple bool).

                    In void timeoutFired(), QTimer::isActive() is used as a proxy assertion that m_pendinghas content.
                    That's a like hazarding a bet that nobody is home, because the doorbell remains unanswered. The proxy assertion bet is lost, when the inhabitant was stuck on the loo ;-) It may be better to check m_pendingdirectly:

                    void timeoutFired()
                        {
                    
                    
                            if (m_pending.isEmpty()) {
                                qDebug() << __FUNCTION__ << "without probes";
                                return;
                            }
                            qDebug() << __FUNCTION << "with" << m_pending.count() << "probes";
                    
                            auto pivot = std::partition(m_pending.begin(),
                                                        m_pending.end(),
                                                        [this](const Probe& probe) {
                                                            return !probe.expired;
                                                        });
                    
                            for (auto it = pivot; it != m_pending.end(); ++it) {
                                process(*it);
                            }
                    
                            m_pending.resize(std::distance(m_pending.begin(), pivot));
                        }
                    

                    If I add logs in the timeoutFired method then they don't get printed in the invocation where it crashes which makes me doubtful that it was called.

                    The stack trace is clear about timeoutFired being the crime scene. So either the source with the qDebug()is newer than the binary or the crash kicks in before qDebug()has had time to speak up.

                    Software Engineer
                    The Qt Company, Oslo

                    S 1 Reply Last reply
                    2
                    • Axel SpoerlA Axel Spoerl

                      @schrute
                      As @Christian-Ehrlicher said, QTimer::timeout can be posted before and delivered after the timer was stopped.
                      QTimer::stop()removes the timer synchronously, which means no more signals are emitted from that moment.
                      Disconnecting a driver when no longer used, is never a bad idea. That could be implemented in a small function stopTimer(). However, it does not prevent previously emitted signals from being delivered.
                      The active property should normally be synchronous, but I am not sure if it can leak a bit behind (it's a computed property and not a simple bool).

                      In void timeoutFired(), QTimer::isActive() is used as a proxy assertion that m_pendinghas content.
                      That's a like hazarding a bet that nobody is home, because the doorbell remains unanswered. The proxy assertion bet is lost, when the inhabitant was stuck on the loo ;-) It may be better to check m_pendingdirectly:

                      void timeoutFired()
                          {
                      
                      
                              if (m_pending.isEmpty()) {
                                  qDebug() << __FUNCTION__ << "without probes";
                                  return;
                              }
                              qDebug() << __FUNCTION << "with" << m_pending.count() << "probes";
                      
                              auto pivot = std::partition(m_pending.begin(),
                                                          m_pending.end(),
                                                          [this](const Probe& probe) {
                                                              return !probe.expired;
                                                          });
                      
                              for (auto it = pivot; it != m_pending.end(); ++it) {
                                  process(*it);
                              }
                      
                              m_pending.resize(std::distance(m_pending.begin(), pivot));
                          }
                      

                      If I add logs in the timeoutFired method then they don't get printed in the invocation where it crashes which makes me doubtful that it was called.

                      The stack trace is clear about timeoutFired being the crime scene. So either the source with the qDebug()is newer than the binary or the crash kicks in before qDebug()has had time to speak up.

                      S Offline
                      S Offline
                      schrute
                      wrote on last edited by
                      #11

                      @Axel-Spoerl The issue was with my build setup. After a clean build the debugger started behaving properly and I was able to resolve the crash.

                      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