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. killTimer: Timers cannot be stopped from another thread
Forum Updated to NodeBB v4.3 + New Features

killTimer: Timers cannot be stopped from another thread

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 4 Posters 834 Views 1 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.
  • D Offline
    D Offline
    DungeonLords
    wrote on last edited by DungeonLords
    #1

    I want to use QTimer in another thread, this is full repo.

    While exit from proj I get error

    QObject::killTimer: Timers cannot be stopped from another thread
    QObject::~QObject: Timers cannot be stopped from another thread
    

    Why? A piece of code from repo.
    Main thread

    connect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection);
    QTimer *askTim(new QTimer(this));
    connect(askTim, &QTimer::timeout, this, [&]{
        qDebug().noquote().nospace() << "thread;askTim;" << QThread::currentThreadId();
        emit GetTimeAsk();
    });
    askTim->start(400);
    

    Worker thread

    void Worker::GetTime(){
        static uint i;
        qDebug().noquote().nospace() << "thread;GetTime;" << QThread::currentThreadId() << ";" << i++;
        tim->start();
    }
    
    1. Looks like problem reason is emit GetTimeAsk() but this signal is connected to slot using Qt::QueuedConnection connection type:
      "Queued Connection The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread"
    connect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection);
    
    1. And threads is really different: emit GetTimeAsk() located in thread 0x7b6260960000 and slot GetTime() is started from 0x7b625ca006c0 thread... Sounds like problem should not be but in log we have
    QObject::killTimer: Timers cannot be stopped from another thread
    QObject::~QObject: Timers cannot be stopped from another thread
    
    1. Insted of Qt::QueuedConnection I have tried Qt::AutoConnection, but problem still the same.
    2. Another idea was that tim= new QTimer(this) is started in incorrect thread but I don't think so because in log I see first thread->start() and then Worker::run.
    3. Anothere idead is to use QScopedPointer: QScopedPointer<QTimer> tim instead of QTimer *tim, but problem is the same.
    jsulmJ 1 Reply Last reply
    0
    • D DungeonLords

      @jsulm thanks, now works, I tested by this code, log is without problem:

      $ ./QThread_QTimer
      Worker::Worker
      MainWindow::MainWindow
      thread->start()
      parents QObject(0x0) MainClass(0x7fff7673c740)
      Worker::run
      ^CWelcome to Signal handled:  2
      requestInterruption
      emit finished()
      ~Worker()
      threadIsFinished
      ~MainWindow()
      

      Should I open bug report about QScopedPointer in multi-thread proj?

      P.S. With std::unique_ptr the same problem like with QScopedPointer...

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #11

      @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

      Should I open bug report about QScopedPointer in multi-thread proj?

      There is no bug.
      It's not the job of the QScopedPointer to know in which thread the object lives which it is managing.
      The correct way in Qt to delete objects living in other threads is to use deleteLater().

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      2
      • D DungeonLords

        I want to use QTimer in another thread, this is full repo.

        While exit from proj I get error

        QObject::killTimer: Timers cannot be stopped from another thread
        QObject::~QObject: Timers cannot be stopped from another thread
        

        Why? A piece of code from repo.
        Main thread

        connect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection);
        QTimer *askTim(new QTimer(this));
        connect(askTim, &QTimer::timeout, this, [&]{
            qDebug().noquote().nospace() << "thread;askTim;" << QThread::currentThreadId();
            emit GetTimeAsk();
        });
        askTim->start(400);
        

        Worker thread

        void Worker::GetTime(){
            static uint i;
            qDebug().noquote().nospace() << "thread;GetTime;" << QThread::currentThreadId() << ";" << i++;
            tim->start();
        }
        
        1. Looks like problem reason is emit GetTimeAsk() but this signal is connected to slot using Qt::QueuedConnection connection type:
          "Queued Connection The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread"
        connect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection);
        
        1. And threads is really different: emit GetTimeAsk() located in thread 0x7b6260960000 and slot GetTime() is started from 0x7b625ca006c0 thread... Sounds like problem should not be but in log we have
        QObject::killTimer: Timers cannot be stopped from another thread
        QObject::~QObject: Timers cannot be stopped from another thread
        
        1. Insted of Qt::QueuedConnection I have tried Qt::AutoConnection, but problem still the same.
        2. Another idea was that tim= new QTimer(this) is started in incorrect thread but I don't think so because in log I see first thread->start() and then Worker::run.
        3. Anothere idead is to use QScopedPointer: QScopedPointer<QTimer> tim instead of QTimer *tim, but problem is the same.
        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #2

        @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

        tim->start();

        Where is tim living (in which thread)? You just have to make sure the timer lives in the thread where it is used. Usually you achieve it by creating it in the thread.

        https://forum.qt.io/topic/113070/qt-code-of-conduct

        D 1 Reply Last reply
        2
        • jsulmJ jsulm

          @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

          tim->start();

          Where is tim living (in which thread)? You just have to make sure the timer lives in the thread where it is used. Usually you achieve it by creating it in the thread.

          D Offline
          D Offline
          DungeonLords
          wrote on last edited by
          #3

          @jsulm askTim located in main thread but it's slot GetTime() is located in worker thread...

          jsulmJ 1 Reply Last reply
          0
          • D DungeonLords

            @jsulm askTim located in main thread but it's slot GetTime() is located in worker thread...

            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #4

            @DungeonLords I asked about tim, not askTim.
            Again: where and when is tim created?

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            D 1 Reply Last reply
            0
            • jsulmJ jsulm

              @DungeonLords I asked about tim, not askTim.
              Again: where and when is tim created?

              D Offline
              D Offline
              DungeonLords
              wrote on last edited by DungeonLords
              #5

              @jsulm tim is created in Worker thread, and as I wrote
              4) Another idea was that tim= new QTimer(this) is started in incorrect thread but I don't think so because in log I see first thread->start() and then Worker::run.

              jsulmJ 1 Reply Last reply
              0
              • D DungeonLords

                @jsulm tim is created in Worker thread, and as I wrote
                4) Another idea was that tim= new QTimer(this) is started in incorrect thread but I don't think so because in log I see first thread->start() and then Worker::run.

                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on last edited by
                #6

                @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

                tim is created in Worker thread

                Are you sure? Can you please show where exactly you're creating it?

                https://forum.qt.io/topic/113070/qt-code-of-conduct

                D 1 Reply Last reply
                0
                • jsulmJ jsulm

                  @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

                  tim is created in Worker thread

                  Are you sure? Can you please show where exactly you're creating it?

                  D Offline
                  D Offline
                  DungeonLords
                  wrote on last edited by DungeonLords
                  #7

                  @jsulm here

                  void Worker::run()
                  {
                      qDebug() << "Worker::run";
                      tim= new QTimer(this); //<<here
                      connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection));
                      tim->setInterval(400);
                      while(1)
                  

                  Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():

                  connect(thread.get(), &QThread::started, worker.get(), &Worker::run);
                  thread->start();
                  
                  Christian EhrlicherC jsulmJ S 3 Replies Last reply
                  0
                  • D DungeonLords

                    @jsulm here

                    void Worker::run()
                    {
                        qDebug() << "Worker::run";
                        tim= new QTimer(this); //<<here
                        connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection));
                        tim->setInterval(400);
                        while(1)
                    

                    Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():

                    connect(thread.get(), &QThread::started, worker.get(), &Worker::run);
                    thread->start();
                    
                    Christian EhrlicherC Online
                    Christian EhrlicherC Online
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by
                    #8

                    @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

                    QTimer(this)

                    So you create it in the main thread as the QThread object lives in the main thread.

                    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
                    • D DungeonLords

                      @jsulm here

                      void Worker::run()
                      {
                          qDebug() << "Worker::run";
                          tim= new QTimer(this); //<<here
                          connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection));
                          tim->setInterval(400);
                          while(1)
                      

                      Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():

                      connect(thread.get(), &QThread::started, worker.get(), &Worker::run);
                      thread->start();
                      
                      jsulmJ Offline
                      jsulmJ Offline
                      jsulm
                      Lifetime Qt Champion
                      wrote on last edited by
                      #9

                      @DungeonLords The problem is probably that you use a scoped pointer for the worker, so it is deleted in main thread. Use raw pointer and connect thread finished signal to deletLater() slot of the worker.

                      https://forum.qt.io/topic/113070/qt-code-of-conduct

                      D 1 Reply Last reply
                      1
                      • jsulmJ jsulm

                        @DungeonLords The problem is probably that you use a scoped pointer for the worker, so it is deleted in main thread. Use raw pointer and connect thread finished signal to deletLater() slot of the worker.

                        D Offline
                        D Offline
                        DungeonLords
                        wrote on last edited by DungeonLords
                        #10

                        @jsulm thanks, now works, I tested by this code, log is without problem:

                        $ ./QThread_QTimer
                        Worker::Worker
                        MainWindow::MainWindow
                        thread->start()
                        parents QObject(0x0) MainClass(0x7fff7673c740)
                        Worker::run
                        ^CWelcome to Signal handled:  2
                        requestInterruption
                        emit finished()
                        ~Worker()
                        threadIsFinished
                        ~MainWindow()
                        

                        Should I open bug report about QScopedPointer in multi-thread proj?

                        P.S. With std::unique_ptr the same problem like with QScopedPointer...

                        jsulmJ 1 Reply Last reply
                        0
                        • D DungeonLords

                          @jsulm thanks, now works, I tested by this code, log is without problem:

                          $ ./QThread_QTimer
                          Worker::Worker
                          MainWindow::MainWindow
                          thread->start()
                          parents QObject(0x0) MainClass(0x7fff7673c740)
                          Worker::run
                          ^CWelcome to Signal handled:  2
                          requestInterruption
                          emit finished()
                          ~Worker()
                          threadIsFinished
                          ~MainWindow()
                          

                          Should I open bug report about QScopedPointer in multi-thread proj?

                          P.S. With std::unique_ptr the same problem like with QScopedPointer...

                          jsulmJ Offline
                          jsulmJ Offline
                          jsulm
                          Lifetime Qt Champion
                          wrote on last edited by
                          #11

                          @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

                          Should I open bug report about QScopedPointer in multi-thread proj?

                          There is no bug.
                          It's not the job of the QScopedPointer to know in which thread the object lives which it is managing.
                          The correct way in Qt to delete objects living in other threads is to use deleteLater().

                          https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply
                          2
                          • D DungeonLords has marked this topic as solved on
                          • D DungeonLords

                            @jsulm here

                            void Worker::run()
                            {
                                qDebug() << "Worker::run";
                                tim= new QTimer(this); //<<here
                                connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection));
                                tim->setInterval(400);
                                while(1)
                            

                            Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():

                            connect(thread.get(), &QThread::started, worker.get(), &Worker::run);
                            thread->start();
                            
                            S Offline
                            S Offline
                            SimonSchroeder
                            wrote on last edited by
                            #12

                            @DungeonLords said in killTimer: Timers cannot be stopped from another thread:

                            void Worker::run()

                            processEvents() in an infinite loop is not the best solution here. This will produce code that will use a single core a 100%. People will start asking questions why your app is using 100% of one core while it is doing nothing (I'm speaking from experience). The proper solution is to call exec() instead. However, this is also already the default implementation of QThread::run(). So, you can just leverage that and throw away your entire while-loop. Maybe then don't call your method run() but just createTimer(). Then it makes a lot more sense to call connect(thread.get(), &QThread::started, worker.get(), &Worker::createTimer());, i.e. createTimer when thread is started. (Instead of using requestInterruption you would then just call quit.)

                            The use of exit_LABEL shows some lack of understanding of asynchronous programming, which is the natural way in Qt. Send signals connected to slots instead to perform such operations. Just out of curiosity: Was AI heavily involved in creating this code? Or are you just coming from embedded systems programming?

                            emit GetTimeAsk(); does not make sense. emit is usually used for signals only (it compiles because it is replaced by nothing by the preprocessor). Effectively you are just executing a normal member function. This also means that this is just executed in the main thread. (Which in turn means that incrementing i is not thread safe.)

                            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