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 1.3k 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 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 Offline
                Christian EhrlicherC Offline
                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