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. Signals and not propagated outside thread
QtWS25 Last Chance

Signals and not propagated outside thread

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 4 Posters 918 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.
  • sierdzioS Offline
    sierdzioS Offline
    sierdzio
    Moderators
    wrote on last edited by
    #2

    @Mark81 said in Signals and not propagated outside thread:

    threadCopier->start();
    Engine engine(&worker, &copier); // this is my main class
    

    You start the thread before the engine has a chance to run the connect calls. This way some of the initial emits of finished() might be missed by the engine.

    (Z(:^

    M 1 Reply Last reply
    3
    • sierdzioS sierdzio

      @Mark81 said in Signals and not propagated outside thread:

      threadCopier->start();
      Engine engine(&worker, &copier); // this is my main class
      

      You start the thread before the engine has a chance to run the connect calls. This way some of the initial emits of finished() might be missed by the engine.

      M Offline
      M Offline
      Mark81
      wrote on last edited by Mark81
      #3

      @sierdzio Actually the copy begins when the user press a PushButton, there are no fires of the finished() signal in the constructor. I forgot to mention in the question - I apologize.

      1 Reply Last reply
      1
      • sierdzioS Offline
        sierdzioS Offline
        sierdzio
        Moderators
        wrote on last edited by
        #4

        @Mark81 said in Signals and not propagated outside thread:

        if (info.isFile())
        {
        _copier->copy(info);

        You are not executing this method in a thread at all! This is a direct call to copy() and it will be executed in your main thread.

        You have to either trigger the copy by a signal-slot connection, or use QObject::invokeMethod() to fire your method in the thread.

        And that explains why the signals are seemingly fired too late - the event loop does not have enough time to process the signals because everything runs on main thread.

        I may be wrong here, of course, I just had a quick look at the code.

        (Z(:^

        1 Reply Last reply
        3
        • M Offline
          M Offline
          Mark81
          wrote on last edited by Mark81
          #5

          Oh, my fault! I thought that because _copier is running in another thread (from main.cpp) any call to its method will run in that thread!

          So, I'm changing the code. I'm not sure about the syntax for registering metatypes to be used with QMetaObject::invokeMethod(). Hence I tried the signal-slot connection.

          I moved the copy function in the public slot section of Copier.h. Then I declared a signal copier_copy(QFileInfo source) in Engine.h and added this code in the cpp:

          qRegisterMetaType<QFileInfo>("QFileInfo");
          connect(this, &Engine::copier_copy, _copier, &Copier::copy);
          // ...
          
          emit copier_copy(info);
          

          but unfortunately the behavior is exactly the same!

          EDIT:

          here the invokeMethod() version:

          qRegisterMetaType<QFileInfo>("QFileInfo");
          // ..
          

          QGenericArgument argument = Q_ARG(QFileInfo, info);
          QMetaObject::invokeMethod(_copier, "copy", argument);

          but nothing has changed.

          1 Reply Last reply
          0
          • M Offline
            M Offline
            Mark81
            wrote on last edited by
            #6

            "Solved" in this way - even I don't fully understand why:

            in copier.cpp

            Copier::Copier(QObject *parent) : QObject(parent)
            {
                //connect(this, &Copier::finished, this, &Copier::copyFile);
                connect(this, &Copier::finished, this, &Copier::copier_finished);
            }
            
            void Copier::copier_finished()
            {
                QTimer::singleShot(0, this, &Copier::copyFile);
            }
            
            1 Reply Last reply
            0
            • dheerendraD Offline
              dheerendraD Offline
              dheerendra
              Qt Champions 2022
              wrote on last edited by
              #7

              I saw your issue. In the first case 'finished' did not reach engine, becz you never allowed the event loop to start in main thread. I felt your code did not move beyond following line.
              "Engine engine(&worker, &copier);"
              You can check this by placing debug statement.

              I felt that you wanted to make the threaded copy of files.

              1. There two threads(main-thread and copy-thread)
              2. Main-thread as engine
              3. Copy-thread has copier
              4. Your idea was, engine should ask the copier to copy the file
              5. Copier should copy the contents of the file. This copy operation should happen in copy-thread.
              6. Copy-thread should emit the signal saying that copy is 'finished'
              7. This finished signal should be caught by main-thread(engine).
              8. Engine should update progress bar. Now Engine should tell the copier again that start copying new file.
              9. Same task repeat till it copies all the files.

              Hope my understanding is correct.

              I felt maintaining separate Queue inside the Copier is unnecessary. Signal-Slots across the thread work using Queue.

              If this is the case, here is sample code for you.

              #include "Copier.h"
              
              Copier::Copier(QObject *parent) : QObject(parent){}
              void Copier::run(){}
              void Copier::copyFile(int fi)
              {
                 qDebug() << Q_FUNC_INFO <<  " File Name =" << fi << " Thread ID=" <<   QThread::currentThreadId() << endl;
                 QThread::sleep(5);// Simulation code. Here copy file code comes. 
                 return copyComplete();
              }
              
              Engine::Engine(QObject *parent) : QObject(parent){}
              
              void Engine::copyComplete()
              {
                 qDebug() << Q_FUNC_INFO << " Copy Complete" <<endl;
                 emit startNextFile(x++);
              }
              
              int main(int argc, char *argv[])
              {
                  QCoreApplication a(argc, argv);
              
                  qDebug() << Q_FUNC_INFO << " Thread ID=" << QThread::currentThreadId() << endl;
              
                  QThread thr;
                  Engine eng;
                  Copier cp;
                  cp.moveToThread(&thr);
                  QObject::connect(&thr,SIGNAL(started()),&cp,SLOT(run()));
                  QObject::connect(&cp,SIGNAL(copyComplete()),&eng,SLOT(copyComplete()));
                  QObject::connect(&eng,SIGNAL(startNextFile(int)),&cp,SLOT(copyFile(int)));
                  thr.start();
                  eng.startNextFile(0);
              
                  return a.exec();
              }
              
              

              Hope this helps.

              Dheerendra
              @Community Service
              Certified Qt Specialist
              http://www.pthinks.com

              1 Reply Last reply
              3
              • M Offline
                M Offline
                Mark81
                wrote on last edited by Mark81
                #8

                It's all correct but point 8. Actually, in my idea the finished() signal is caught by both copier and engine. Copier will start automatically the next queued file (if any), and engine will update the progress bar only.

                In this way I can append new files to be copied everywhere in the program without worrying about the current state. For this reason I kept the queue in the copier class. Anyway your suggestion should work in a simplified case.

                1 Reply Last reply
                0
                • sierdzioS Offline
                  sierdzioS Offline
                  sierdzio
                  Moderators
                  wrote on last edited by
                  #9

                  @dheerendra great post, thanks for chiming in!

                  @Mark81 said in Signals and not propagated outside thread:

                  QGenericArgument argument = Q_ARG(QFileInfo, info);

                  Never use QGenericArgument, it is an internal symbol of Qt. You should just use Q_ARG directly in invokeMethod, however ugly it might look ;-)

                  (Z(:^

                  JKSHJ 1 Reply Last reply
                  2
                  • sierdzioS sierdzio

                    @dheerendra great post, thanks for chiming in!

                    @Mark81 said in Signals and not propagated outside thread:

                    QGenericArgument argument = Q_ARG(QFileInfo, info);

                    Never use QGenericArgument, it is an internal symbol of Qt. You should just use Q_ARG directly in invokeMethod, however ugly it might look ;-)

                    JKSHJ Offline
                    JKSHJ Offline
                    JKSH
                    Moderators
                    wrote on last edited by
                    #10

                    @sierdzio said in Signals and not propagated outside thread:

                    You should just use Q_ARG directly in invokeMethod, however ugly it might look ;-)

                    Alternatively, you can use lambdas with QMetaObject::invokeMethod() since Qt 5.10: http://doc.qt.io/qt-5/qmetaobject.html#invokeMethod-4 (No more Q_ARGs!)

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

                    1 Reply Last reply
                    1
                    • dheerendraD Offline
                      dheerendraD Offline
                      dheerendra
                      Qt Champions 2022
                      wrote on last edited by
                      #11

                      Additional information. You can keep sending the file names to copier. They will be automatically queued and slot will be executed. It is not like filenames need to be sent once the copy is complete. Engine can keep sending them.

                      Dheerendra
                      @Community Service
                      Certified Qt Specialist
                      http://www.pthinks.com

                      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