1

I have a simple application that uses one worker thread. This worker thread is started and initializes DownloadManager, which is responsible for downloading files from the net. In my main application class I have the finished() SIGNAL on the thread that is emitted before the DownloadManager finishes.

My question is how to make the worker thread wait until the DownloadManager finishes its work.

Here is example code :

 class Main
 {
     m_DownloadWorker = new DownloadWorker(this);
     QObject::connect(pm_hotosDownloadWorker, SIGNAL(finished()), this, SLOT(DownloadWorkerFinished()));
     m_DownloadWorker->Execute();
     // do i need to do here something so the thread will wait ?

     .....


    void Main::DownloadWorkerFinished()
    {
        Log("DownloadWorkerFinished");
    }
 };


 class DownloadWorker : public QThread
 {
     void DownloadWorker::Execute()
     {

         // do i need to do here somthing so the thread will wait ? 
        start();
     }

     void DownloadWorker::run()
     {
         // do i need to do here somthing so the thread will wait ?
        DownloadManager* pDownloadManager = new DownloadManager(this);
        pDownloadManager->download();


     }
 };

 class DownloadManager: public QObject
 {
     // downloading stuff using Qt networkmanager 

     .....
     .....
 }
user63898
  • 29,839
  • 85
  • 272
  • 514
  • this is very confusing. 1) what is pm_hotosDownloadWorker? 2) What does QObject::connect(pm_hotosDownloadWorker, SIGNAL(finished()), this, SLOT(DownloadWorkerFinished())); mean? What happens inside DownloadWorker::start()? 3) in order to find out if you have to do something to make the thread wait, test if if you need to something by comparing your expectations to what really happens / the docu says should happen. 4) Why are there 3 spots where you want to block execution? – Ronny Brendel Apr 10 '11 at 09:20
  • 1) i fixed it 2)it just print massage that the thread is finished 3) ... 4) i what the thread will finish only when the downloads from the DownloadManager are done – user63898 Apr 10 '11 at 10:23

2 Answers2

5

In cases when you have a signal that is emitted when an asynchronous operation is completed, you can always use QEventLoop to "turn" the asynchronous operation into synchronous with the current thread. It is still asynchronous, but the thread will "wait" for it to finish.

QNetworkAccessManager nam;
QEventLoop loop;
QNetworkReply *reply = nam.get(request); 
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();

So basically you put this in you DownloadManager class where you want to do a network request synchronously. exec() will return once the loop's quit slot has been called.

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180
  • i allready have function in my finish SLOT , how can i do it then? – user63898 Apr 10 '11 at 10:30
  • You mean signal, right? You can connect multiple slots to a single signal, no problem. – Tamás Szelei Apr 10 '11 at 11:51
  • nam.get() is called before signal connected to loops quit slot. It is not imposible that finished signal is called before loop.exec() or connect statemet is called.Q1: what happens if the signal is emmited before connect ? Q2 : what happens when signal is emitted before exec() and after connect() ? @TamásSzelei – Muhammet Ali Asan Feb 21 '17 at 15:30
  • @MuhammetAliAsan Both your questions boil down to this: isn't there a race condition here? That depends on where this code executes. If this code runs in a thread separately from the application's main event loop, then a race condition may happen. If this code runs in the main event loop (e.g. in a button click slot) then there can be no race condition because any events by the reply will only be processed after the current event is finished (the very function we are in). – Tamás Szelei Feb 21 '17 at 19:07
3

You can use QThread::exec() call to run your thread in the event loop. The thread will run it until you tell your thread to exit by calling QThread::exit(). So some sample code can look like this:

void DownloadWorker::run()
 {
    DownloadManager* pDownloadManager = new DownloadManager(this);
    connect(pDownloadManager, SIGNAL(finished()), SLOT(exit()));
    connect(pDownloadManager, SIGNAL(error()), SLOT(exit()));
    pDownloadManager->download();
    exec();
 }

That would guarantee you that your thread won't quit until the "finished()" signal of your DownloadManager is issued.

Note: Here I put an example of how to solve your problem but I don't know your whole app code. That means there is not guarantee this code is thread safe and consistent. You need to take care of the mutexes and all the correct synchronization yourself. Be very careful ! Working with such a "low level" thread API requites good understanding of multithereading.

Hope that helps

Barbaris
  • 1,256
  • 7
  • 7