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

QThread and timers

Scheduled Pinned Locked Moved General and Desktop
25 Posts 5 Posters 13.0k 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.
  • G Offline
    G Offline
    goli
    wrote on last edited by
    #1

    I created a QThread in the main thread. In this thread i run a timer with event loop to do some calculation.
    When I end the application I get the warrning:
    @QObject::killTimers: timers cannot be stopped from another thread
    @

    This warrning appear only on windows, and not on my embedded linux device.
    Any idea why, and how to fix this error?

    1 Reply Last reply
    0
    • A Offline
      A Offline
      astodolski
      wrote on last edited by
      #2

      I too get the same issue. I am running 4.8.4 with Windows 7.1 SDK compiler on Windows 7 x86 machine. Qt bug perhaps? Another user who's been helping with this issue doesn't see it all on Linux x64 running both v 4.8 and 5.0 RC2

      1 Reply Last reply
      0
      • G Offline
        G Offline
        goli
        wrote on last edited by
        #3

        Did you solve this issue some how?

        1 Reply Last reply
        0
        • A Offline
          A Offline
          astodolski
          wrote on last edited by
          #4

          No not at all! Very frustrating.

          1 Reply Last reply
          0
          • JKSHJ Offline
            JKSHJ Offline
            JKSH
            Moderators
            wrote on last edited by
            #5

            Please share your code that shows:

            Where is your QTimer constructed?

            Where is your QTimer destroyed?

            Remember, a QThread object is not a thread: It lives in the main thread -- it doesn't live in the other thread. Which means:

            An object that is created in the QThread's constructor will live in the main thread

            An object that is destroyed with the QThread is destroyed from the main thread

            Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

            1 Reply Last reply
            0
            • A Offline
              A Offline
              astodolski
              wrote on last edited by
              #6

              I would like to post a complete test app which illustrates the condition. The error is when the stop() slot is called. It appears to be called twice but that's another discussion. On the first call of the stop slot, killTimer calls unregisterTimer which gets to line 957 of qeventdispatcher_win.cpp. (Windows only?) This is where @thread() != QThread::currentThread;@

              on a second call the current thread equals the worker thread. I'm not seeing how to post a sample attachment. Is this allowed?

              1 Reply Last reply
              0
              • P Offline
                P Offline
                Peter K
                wrote on last edited by
                #7

                Make sure you stop the timer in the thread it lives in.

                Is the timer a member of a derived QObject or a derived QThread? Note that the QThread object itself lives in the main thread, so it's timers should be deleted in the main thread.

                1 Reply Last reply
                0
                • JKSHJ Offline
                  JKSHJ Offline
                  JKSH
                  Moderators
                  wrote on last edited by
                  #8

                  There's no way to attach files at this time, but if you can make a minimal test case, feel free to paste the code straight into your reply (just use the '@' tags like you did in your last post)

                  Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    astodolski
                    wrote on last edited by
                    #9

                    OK, Let's see how well this illustrates what I have going on:

                    worker.h

                    @
                    class Worker : public QObject
                    {
                    Q_OBJECT
                    public:
                    explicit Worker(QObject *parent = 0);
                    virtual ~Worker();

                    signals:
                    void finished();
                    void updateProgress(int);

                    public slots:
                    void start();
                    void stop();
                    void doWork();

                    private:
                    QTimer* m_workerTimer;
                    int m_tid;
                    void timerEvent(QTimerEvent *ev);
                    };
                    @

                    worker.cpp

                    @
                    #include "worker.h"
                    #include <QThread>
                    #include <QDebug>

                    volatile bool stopWork;

                    Worker::Worker(QObject *parent) : QObject(parent)
                    {
                    stopWork = false;
                    }

                    Worker::~Worker()
                    {

                    }

                    void Worker::start()
                    {
                    m_tid = startTimer(100);
                    }

                    void Worker::stop()
                    {
                    killTimer(m_tid);
                    stopWork = true;
                    }

                    void Worker::doWork()
                    {
                    for (int i = 0; i < 1000000; i++)
                    {
                    if (stopWork)
                    {
                    break;
                    }

                        if (i % 10000 == 0)
                        {
                            emit updateProgress((i / 10000) + 1);
                            qDebug() << ((i / 10000) + 1);
                            static_cast<MThread*>(QThread::currentThread())->msleep(20);
                        }
                    }
                    
                    emit finished();
                    

                    }

                    void Worker::timerEvent(QTimerEvent* ev)
                    {
                    if(ev->timerId() == m_tid)
                    doWork();
                    else
                    QObject::timerEvent(ev);
                    }
                    @

                    flashwizard.h

                    @
                    #ifndef FLASHWIZARD_H
                    #define FLASHWIZARD_H

                    #include <QWizard>
                    #include <QtCore>
                    #include <QThread>
                    #include "worker.h"

                    namespace Ui
                    {
                    class FlashWizard;
                    }

                    class FlashWizard : public QWizard
                    {
                    Q_OBJECT

                    public:
                    explicit FlashWizard(QWidget* parent = 0);
                    virtual ~FlashWizard();

                    enum { Page_Intro, Page_Program};
                    

                    public slots:
                    void updateWritingProgressBar(const int value);
                    void updateLabel(const QString& value);
                    void pageCleanUp(int id);
                    void reject();

                    private:
                    Ui::FlashWizard* ui;
                    bool convertedOK;
                    Worker* worker;
                    QThread workerThread;

                    };

                    #endif // FLASHWIZARD_H

                    @

                    flashwizard.cpp

                    @
                    #include "flashwizard.h"
                    #include "ui_flashwizard.h"
                    #include "worker.h"

                    #include <QThread>
                    #include <QDebug>
                    #include <QMessageBox>

                    FlashWizard::FlashWizard(QWidget *parent) : QWizard(parent), ui(new Ui::FlashWizard)
                    {
                    ui->setupUi(this);

                    ui->pbReading->reset();
                    ui->pbWriting->reset();
                    
                    ui->lblReadingStatus->setText("");
                    ui->lblReadingStatus->setText("");
                    ui->lblProgStatus->setText("");
                    
                    connect(ui->introPage, SIGNAL(p1_updateLabelOne(const QString&)), this, SLOT(updateLabel(const QString&)));
                    connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(pageCleanUp(int)));
                    
                    worker = new Worker;
                    worker->moveToThread(&workerThread);
                    
                    qDebug() << "Worker Object Thread Id: "<< worker->thread();
                    
                    connect(&workerThread, SIGNAL(started()), worker, SLOT(start()));
                    connect(&workerThread, SIGNAL(finished()), worker, SLOT(stop()));
                    connect(worker, SIGNAL(finished()), &workerThread, SLOT(quit()));
                    connect(worker, SIGNAL(finished()), ui->programPage, SLOT(setDone()));
                    connect(worker, SIGNAL(updateProgress(int)), this, SLOT(updateWritingProgressBar(int)));
                    

                    }

                    FlashWizard::~FlashWizard()
                    {
                    delete ui;
                    }

                    void FlashWizard::updateWritingProgressBar(const int value)
                    {
                    if (ui->pbWriting->maximum() == value)
                    ui->pbWriting->hide();
                    ui->pbWriting->setValue(value);
                    }

                    void FlashWizard::updateLabel(const QString &value)
                    {
                    ui->lblReadingStatus->setText(value);
                    }

                    void FlashWizard::pageCleanUp(int id)
                    {
                    if (id == Page_Program)
                    {
                    ui->lblProgStatus->setText("Updating ScanX");
                    workerThread.start();
                    qDebug() << "Now using thread: " << worker->thread();
                    }

                    ui->pbReading->setVisible(false);
                    ui->lblUpdating->setText("");
                    

                    }

                    void FlashWizard::reject()
                    {
                    worker->stop();
                    }

                    @

                    It's a wizard that displays a progress bar in the second page and when the cancel button is clicked, the worker should stop - which it does but I get the killTimer message.

                    1 Reply Last reply
                    0
                    • JKSHJ Offline
                      JKSHJ Offline
                      JKSH
                      Moderators
                      wrote on last edited by
                      #10

                      [quote author="astodolski" date="1356056195"]
                      @
                      void FlashWizard::reject()
                      {
                      worker->stop();
                      }@
                      [/quote]That's a direct function call. Your main thread executes FlashWizard::reject(), thus it will also execute Worker::stop(), thus it will also execute Worker::killTimer(). In other words, the program is attempting to kill the timer from the main thread.

                      To execute Worker::stop() in your other thread, connect the your button's clicked() signal to Worker::stop(). You can get rid of FlashWizard::reject() altogether.

                      Edit: To clarify, a slot is just a regular C++ function. It is technically possible to call a slot from any thread, but we usually don't want this. To make the call safely, we use a queued signal-slot connection -- Qt notifies the event loop of the "correct" thread when the signal is emitted, and the slot is then called from that thread

                      Looks like there is a bug in Qt though, if the Linux implementation fails to warn the developer about the cross-thread timer manipulation!

                      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                      1 Reply Last reply
                      0
                      • L Offline
                        L Offline
                        lgeyer
                        wrote on last edited by
                        #11

                        It should indeed warn on Linux as well. Did you define QT_NO_DEBUG to suppress the warning?

                        1 Reply Last reply
                        0
                        • A Offline
                          A Offline
                          astodolski
                          wrote on last edited by
                          #12

                          [quote author="JKSH" date="1356061869"][quote author="astodolski" date="1356056195"]
                          @
                          void FlashWizard::reject()
                          {
                          worker->stop();
                          }@
                          [/quote]That's a direct function call. Your main thread executes FlashWizard::reject(), thus it will also execute Worker::stop(), thus it will also execute Worker::killTimer(). In other words, the program is attempting to kill the timer from the main thread.

                          To execute Worker::stop() in your other thread, connect the your button's clicked() signal to Worker::stop(). You can get rid of FlashWizard::reject() altogether.

                          Edit: To clarify, a slot is just a regular C++ function. It is technically possible to call a slot from any thread, but we usually don't want this. To make the call safely, we use a queued signal-slot connection -- Qt notifies the event loop of the "correct" thread when the signal is emitted, and the slot is then called from that thread

                          Looks like there is a bug in Qt though, if the Linux implementation fails to warn the developer about the cross-thread timer manipulation![/quote]

                          I tried doing it this way:

                          @connect(button(QWizard::CancelButton), SIGNAL(clicked()), worker, SLOT(stop()));@

                          I get an error:

                          C2664: 'bool QObject::connect(const QObject *,const char *,const QObject *,const char *,Qt::ConnectionType)' : cannot convert parameter 1 from 'QAbstractButton *' to 'const QObject *'
                          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

                          I casted the button to QObject* and the slot does not get executed when I click the Wizard cancel button.

                          1 Reply Last reply
                          0
                          • A Offline
                            A Offline
                            astodolski
                            wrote on last edited by
                            #13

                            [quote author="Lukas Geyer" date="1356075094"]It should indeed warn on Linux as well. Did you define QT_NO_DEBUG to suppress the warning?[/quote]

                            No I didn't try that - good to know. I prefer to understand and prevent the warning. Thanks for the tip.

                            Could be a Qt bug.

                            1 Reply Last reply
                            0
                            • JKSHJ Offline
                              JKSHJ Offline
                              JKSH
                              Moderators
                              wrote on last edited by
                              #14

                              [quote author="astodolski" date="1356188428"]I tried doing it this way:

                              @connect(button(QWizard::CancelButton), SIGNAL(clicked()), worker, SLOT(stop()));@

                              I get an error:

                              C2664: 'bool QObject::connect(const QObject *,const char *,const QObject *,const char *,Qt::ConnectionType)' : cannot convert parameter 1 from 'QAbstractButton *' to 'const QObject *'
                              Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

                              I casted the button to QObject* and the slot does not get executed when I click the Wizard cancel button.[/quote]Hmm... QAbstractButton inherits QWidget which inherits QObject, so it should work. Perhaps QAbstractButton was simply forward-declared by the QWizard header. Try adding #include <QAbstractButton>

                              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                              1 Reply Last reply
                              0
                              • L Offline
                                L Offline
                                lgeyer
                                wrote on last edited by
                                #15

                                [quote author="astodolski" date="1356188639"][quote author="Lukas Geyer" date="1356075094"]It should indeed warn on Linux as well. Did you define QT_NO_DEBUG to suppress the warning?[/quote]
                                No I didn't try that - good to know. I prefer to understand and prevent the warning. Thanks for the tip.[/quote]

                                Please do not misunderstand me: I do not recommend using QT_NO_DEBUG to supress the warning. I was just curious why you didn't get the warning on your embedded device, and one reason might be that you have QT_NO_DEBUG defined.

                                1 Reply Last reply
                                0
                                • A Offline
                                  A Offline
                                  astodolski
                                  wrote on last edited by
                                  #16

                                  [quote author="Lukas Geyer" date="1356255159"][quote author="astodolski" date="1356188639"][quote author="Lukas Geyer" date="1356075094"]It should indeed warn on Linux as well. Did you define QT_NO_DEBUG to suppress the warning?[/quote]
                                  No I didn't try that - good to know. I prefer to understand and prevent the warning. Thanks for the tip.[/quote]

                                  Please do not misunderstand me: I do not recommend using QT_NO_DEBUG to supress the warning. I was just curious why you didn't get the warning on your embedded device, and one reason might be that you have QT_NO_DEBUG defined.[/quote]

                                  I don't target an embedded device - I'm targeting Desktop.

                                  1 Reply Last reply
                                  0
                                  • A Offline
                                    A Offline
                                    astodolski
                                    wrote on last edited by
                                    #17

                                    [quote author="JKSH" date="1356229131"][quote author="astodolski" date="1356188428"]I tried doing it this way:

                                    @connect(button(QWizard::CancelButton), SIGNAL(clicked()), worker, SLOT(stop()));@

                                    I get an error:

                                    C2664: 'bool QObject::connect(const QObject *,const char *,const QObject *,const char *,Qt::ConnectionType)' : cannot convert parameter 1 from 'QAbstractButton *' to 'const QObject *'
                                    Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

                                    I casted the button to QObject* and the slot does not get executed when I click the Wizard cancel button.[/quote]Hmm... QAbstractButton inherits QWidget which inherits QObject, so it should work. Perhaps QAbstractButton was simply forward-declared by the QWizard header. Try adding #include <QAbstractButton>[/quote]

                                    @
                                    connect((QObject*)button(QWizard::CancelButton), SIGNAL(clicked()), worker, SLOT(stop()));
                                    @

                                    The Cancel button has no effect on the process. I also included:

                                    @#include <QAbstractButton>@

                                    1 Reply Last reply
                                    0
                                    • G Offline
                                      G Offline
                                      goli
                                      wrote on last edited by
                                      #18

                                      I have embedded device, and I don't get this warrning on the device.
                                      This is my code:
                                      @
                                      .h file:

                                      #include <QObject>
                                      #include <QThread>

                                      class ThreadManager: public QObject
                                      {
                                      Q_OBJECT

                                      public:
                                      explicit ThreadManager();
                                      virtual ~ThreadManager();

                                      inline void startTheThread()
                                      {
                                          m_thread->start();
                                      }
                                      

                                      protected:
                                      virtual void run() = 0;

                                      private slots:
                                      void exec();

                                      private:
                                      QThread* m_thread;
                                      };

                                      .cpp file:

                                      ThreadManager::ThreadManager():
                                      QObject()
                                      {
                                      m_thread = new QThread();
                                      moveToThread(m_thread);
                                      connect(m_thread, SIGNAL(started()), this, SLOT(exec()));
                                      connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater()));
                                      }

                                      ThreadManager::~ThreadManager()
                                      {
                                      m_thread->quit();
                                      }

                                      void ThreadManager::exec()
                                      {
                                      run();
                                      }
                                      @

                                      I create a class that inherit ThreadManager and in the run() function I create a timer with timerEvent:
                                      @
                                      startTimer(1000);
                                      @

                                      when the program end I get this warrning...

                                      1 Reply Last reply
                                      0
                                      • JKSHJ Offline
                                        JKSHJ Offline
                                        JKSH
                                        Moderators
                                        wrote on last edited by
                                        #19

                                        [quote author="astodolski" date="1356287500"]
                                        @
                                        connect((QObject*)button(QWizard::CancelButton), SIGNAL(clicked()), worker, SLOT(stop()));
                                        @

                                        The Cancel button has no effect on the process.[/quote]I notice you have a custom Qt Designer UI for your FlashWizard. Are you still using the QWizard's built-in Cancel button, or did you implement a new one in Qt Designer? button(QWizard::CancelButton) returns a pointer to the built-in button, but this button doesn't exist if you implemented your own UI.

                                        Also, the (QObject*) typecast is unnecessary -- the compiler should cast it for you automatically. Furthermore, if you ever need to make an explicit typecast, using qobject_cast<> is safer, as Qt will perform a run-time check to see if the cast is valid.

                                        [quote author="goli" date="1356332295"]I create a class that inherit ThreadManager and in the run() function I create a timer with timerEvent:
                                        @
                                        startTimer(1000);
                                        @

                                        when the program end I get this warrning...[/quote]QThread IS a thread manager (see http://qt-project.org/doc/qt-5.0/qtcore/qthread.html for a full description, and a small example on how to use QThread). Your code is wrapping a thread manager in a thread manager, so I recommend redesigning it.

                                        Read astodolski's code from 21 December and my reply (http://qt-project.org/forums/viewthread/22916/#107177 ) -- is your issue the same?

                                        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                        1 Reply Last reply
                                        0
                                        • G Offline
                                          G Offline
                                          goli
                                          wrote on last edited by
                                          #20

                                          JKSH , Thank you for your reply.
                                          I don't have the same issue as astodolski. I create the timer in the run() function of the thread(even if I do it without thread manager).
                                          I do it this way to create a event loop for the thread that is saperate from the main thread(GUI thread).
                                          when I try to get the "finished()":http://qt-project.org/doc/qt-5.0/qtcore/qthread.html#finished signal and then kill the timer, I get this warrning, but not all the time...sometimes it appear and sometimes not.

                                          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