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. QBasicTimer::start: Timers cannot be started from another thread issue
Qt 6.11 is out! See what's new in the release blog

QBasicTimer::start: Timers cannot be started from another thread issue

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 2 Posters 8.5k 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.
  • Cobra91151C Cobra91151

    Hi! The code works but I get the issue - QBasicTimer::start: Timers cannot be started from another thread. It occurs when I use QEventLoop in the thread.

    Code:

    void Test::checkDBUpdate()
    {
        QEventLoop *checkDBEventLoop;
        QFile *dbFile = new QFile(QString(DB_DIR) + QString(DB_FILE));
        dbFile->open(QIODevice::ReadOnly);
        QTextStream dbTextStream(dbFile);
        QString localDBFile = dbTextStream.readAll();
        QString ftpDBFile = "";
        checkDBEventLoop = new QEventLoop(this);
        QNetworkReply *checkDBReply = netManager->get(QNetworkRequest(dbFtpUrl()));
        connect(checkDBReply, &QNetworkReply::finished, checkDBEventLoop, &QEventLoop::quit);
        checkDBEventLoop->exec();
    
        if (checkDBReply->bytesAvailable()) {
            ftpDBFile = checkDBReply->readAll();
            qDebug() << localDBFile.length();
            qDebug() << ftpDBFile.length();
    
            if (localDBFile.length() != ftpDBFile.length()) {
                emit dbUpdateAvailable();
            } else {
                emit dbLatest();
            }
        }
    
        dbFile->close();
        delete dbFile;
        delete checkDBReply;
        delete checkDBEventLoop;
    }
    

    I don't have any timers set. How to fix the issue? Thanks.

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

    @Cobra91151 Why do you need an event loop? Why not just use Qt in the way it was designed: asynchronously?

    Do you start any threads?

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

    Cobra91151C 1 Reply Last reply
    0
    • jsulmJ jsulm

      @Cobra91151 Why do you need an event loop? Why not just use Qt in the way it was designed: asynchronously?

      Do you start any threads?

      Cobra91151C Offline
      Cobra91151C Offline
      Cobra91151
      wrote on last edited by
      #3

      @jsulm

      Yes. The work starts in the thread with connected signals and slots. I use QEventLoop to maintain all check work in the checkDBUpdate() slot.

      jsulmJ 1 Reply Last reply
      0
      • Cobra91151C Cobra91151

        @jsulm

        Yes. The work starts in the thread with connected signals and slots. I use QEventLoop to maintain all check work in the checkDBUpdate() slot.

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

        @Cobra91151 Can you show where and how you start the thread?

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

        Cobra91151C 1 Reply Last reply
        0
        • jsulmJ jsulm

          @Cobra91151 Can you show where and how you start the thread?

          Cobra91151C Offline
          Cobra91151C Offline
          Cobra91151
          wrote on last edited by
          #5

          @jsulm

          Ok.

          Code:

          void AppSettings::checkDatabaseUpdate()
          {
              QThread *dbUpdateThread = new QThread();
              Test *dbUpdate = new Test();
              dbUpdate->moveToThread(dbUpdateThread);
              connect(dbUpdateThread, &QThread::started, dbUpdate, &Test::checkDBUpdate);
              connect(dbUpdate, &Test::dbUpdateAvailable, this, &AppSettings::setDBUpdate);
              connect(this, &AppSettings::dbUpdateConfirmed, dbUpdate, &Test::updateDatabase);
              connect(dbUpdate, &Test::updateDBCompleted, this, &AppSettings::setDBUpdated);
              connect(dbUpdate, &Test::dbLatest, this, &AppSettings::setDBLatest);
              connect(this, &AppSettings::dbUpdateCanceled, dbUpdate, &Test::setUpdateCanceled);
              connect(dbUpdate, &Test::updateDBFinished, dbUpdateThread, &QThread::quit);
              connect(dbUpdate, &Test::updateDBFinished, dbUpdate, &Test::deleteLater);
              connect(dbUpdateThread, &QThread::finished, dbUpdateThread, &QThread::deleteLater);
              dbUpdateThread->start();
          }
          
          jsulmJ 1 Reply Last reply
          0
          • Cobra91151C Cobra91151

            @jsulm

            Ok.

            Code:

            void AppSettings::checkDatabaseUpdate()
            {
                QThread *dbUpdateThread = new QThread();
                Test *dbUpdate = new Test();
                dbUpdate->moveToThread(dbUpdateThread);
                connect(dbUpdateThread, &QThread::started, dbUpdate, &Test::checkDBUpdate);
                connect(dbUpdate, &Test::dbUpdateAvailable, this, &AppSettings::setDBUpdate);
                connect(this, &AppSettings::dbUpdateConfirmed, dbUpdate, &Test::updateDatabase);
                connect(dbUpdate, &Test::updateDBCompleted, this, &AppSettings::setDBUpdated);
                connect(dbUpdate, &Test::dbLatest, this, &AppSettings::setDBLatest);
                connect(this, &AppSettings::dbUpdateCanceled, dbUpdate, &Test::setUpdateCanceled);
                connect(dbUpdate, &Test::updateDBFinished, dbUpdateThread, &QThread::quit);
                connect(dbUpdate, &Test::updateDBFinished, dbUpdate, &Test::deleteLater);
                connect(dbUpdateThread, &QThread::finished, dbUpdateThread, &QThread::deleteLater);
                dbUpdateThread->start();
            }
            
            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #6

            @Cobra91151 Is netManager initialized in Test constructor? If so try to do it in Test::checkDBUpdate().
            I do not see any reason to start a thread in AppSettings::checkDatabaseUpdate() which executes a blocking method. Just make Test::checkDBUpdate() non blocking. You really over complicate things.

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

            Cobra91151C 1 Reply Last reply
            0
            • jsulmJ jsulm

              @Cobra91151 Is netManager initialized in Test constructor? If so try to do it in Test::checkDBUpdate().
              I do not see any reason to start a thread in AppSettings::checkDatabaseUpdate() which executes a blocking method. Just make Test::checkDBUpdate() non blocking. You really over complicate things.

              Cobra91151C Offline
              Cobra91151C Offline
              Cobra91151
              wrote on last edited by
              #7

              @jsulm

              Yes, netManager (QNetworkAccessManager) is initialized in the Test constructor. I have initialized it in the constructor to access not only for the Test::checkDBUpdate(), but also for the other features which require QNetworkAccessManager. So I can't initialized it twice or in Test::checkDBUpdate().

              AppSettings class is a GUI window and I connect it there to get the result of the work. It's very big and complicated application.

              What do you mean by blocking method?

              jsulmJ 2 Replies Last reply
              0
              • Cobra91151C Cobra91151

                @jsulm

                Yes, netManager (QNetworkAccessManager) is initialized in the Test constructor. I have initialized it in the constructor to access not only for the Test::checkDBUpdate(), but also for the other features which require QNetworkAccessManager. So I can't initialized it twice or in Test::checkDBUpdate().

                AppSettings class is a GUI window and I connect it there to get the result of the work. It's very big and complicated application.

                What do you mean by blocking method?

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

                @Cobra91151 I mean void Test::checkDBUpdate() is blocking (not returning) until it is finished (that's why you use event loop there, right?). So, you start a thread to execute a blocking method to not block main thread instead of simply making void Test::checkDBUpdate() non blocking. You introduce a complex and error prone work-around (thread) for something you could simply change. Also: why do you use new so often (for example there is no need to allocate dbFile on the heap)? Why not just allocate memory on the stack?

                Back to this timer issue: you create netManager in constructor and then later move Test to another thread, I guess netManager is still in the main thread.

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

                1 Reply Last reply
                1
                • Cobra91151C Cobra91151

                  @jsulm

                  Yes, netManager (QNetworkAccessManager) is initialized in the Test constructor. I have initialized it in the constructor to access not only for the Test::checkDBUpdate(), but also for the other features which require QNetworkAccessManager. So I can't initialized it twice or in Test::checkDBUpdate().

                  AppSettings class is a GUI window and I connect it there to get the result of the work. It's very big and complicated application.

                  What do you mean by blocking method?

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

                  @Cobra91151 Here a non-blocking solution without any threads (untested!):

                  void Test::checkDBUpdate()
                  {
                      QFile dbFile(QString(DB_DIR) + QString(DB_FILE));
                      dbFile.open(QIODevice::ReadOnly);
                      QTextStream dbTextStream(dbFile);
                      QString localDBFile = dbTextStream.readAll();
                      QNetworkReply *checkDBReply = netManager->get(QNetworkRequest(dbFtpUrl()));
                      connect(checkDBReply, &QNetworkReply::finished, [checkDBReply, localDBFile]() {
                          if (checkDBReply->bytesAvailable()) {
                              QString ftpDBFile = checkDBReply->readAll();
                              qDebug() << ftpDBFile.length();
                  
                              if (localDBFile.length() != ftpDBFile.length()) {
                                  emit dbUpdateAvailable();
                              } else {
                                  emit dbLatest();
                              }
                          }
                          checkDBReply->deleteLater();
                      });
                  }
                  
                  void AppSettings::checkDatabaseUpdate()
                  {
                      Test *dbUpdate = new Test();
                      connect(dbUpdate, &Test::dbUpdateAvailable, this, &AppSettings::setDBUpdate);
                      connect(this, &AppSettings::dbUpdateConfirmed, dbUpdate, &Test::updateDatabase);
                      connect(dbUpdate, &Test::updateDBCompleted, this, &AppSettings::setDBUpdated);
                      connect(dbUpdate, &Test::dbLatest, this, &AppSettings::setDBLatest);
                      connect(this, &AppSettings::dbUpdateCanceled, dbUpdate, &Test::setUpdateCanceled);
                      connect(dbUpdate, &Test::updateDBFinished, dbUpdateThread, &QThread::quit);
                      connect(dbUpdate, &Test::updateDBFinished, dbUpdate, &Test::deleteLater);
                      dbUpdate->checkDBUpdate();
                  }
                  

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

                  1 Reply Last reply
                  4
                  • Cobra91151C Offline
                    Cobra91151C Offline
                    Cobra91151
                    wrote on last edited by Cobra91151
                    #10

                    @jsulm

                    Thanks for the code but I get errors:

                    error: C4573: the usage of 'CheckUpdates::dbUpdateAvailable' requires the compiler to capture 'this' but the current default capture mode does not allow it
                    

                    When changing lambda to connect(checkDBReply, &QNetworkReply::finished, [checkDBReply, this]() { I get error:

                    error: C3493: 'localDBFile' cannot be implicitly captured because no default capture mode has been specified
                    
                    jsulmJ 1 Reply Last reply
                    0
                    • Cobra91151C Cobra91151

                      @jsulm

                      Thanks for the code but I get errors:

                      error: C4573: the usage of 'CheckUpdates::dbUpdateAvailable' requires the compiler to capture 'this' but the current default capture mode does not allow it
                      

                      When changing lambda to connect(checkDBReply, &QNetworkReply::finished, [checkDBReply, this]() { I get error:

                      error: C3493: 'localDBFile' cannot be implicitly captured because no default capture mode has been specified
                      
                      jsulmJ Offline
                      jsulmJ Offline
                      jsulm
                      Lifetime Qt Champion
                      wrote on last edited by
                      #11

                      @Cobra91151 said in QBasicTimer::start: Timers cannot be started from another thread issue:

                      connect(checkDBReply, &QNetworkReply::finished, checkDBReply, this {

                      Why did you remove localDBFile?

                      connect(checkDBReply, &QNetworkReply::finished, [checkDBReply, localDBFile, this]() {
                      

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

                      Cobra91151C 1 Reply Last reply
                      3
                      • jsulmJ jsulm

                        @Cobra91151 said in QBasicTimer::start: Timers cannot be started from another thread issue:

                        connect(checkDBReply, &QNetworkReply::finished, checkDBReply, this {

                        Why did you remove localDBFile?

                        connect(checkDBReply, &QNetworkReply::finished, [checkDBReply, localDBFile, this]() {
                        
                        Cobra91151C Offline
                        Cobra91151C Offline
                        Cobra91151
                        wrote on last edited by
                        #12

                        @jsulm

                        Yes, you right. I missed it. Now it works. Thank you.

                        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