0

Lets say I have a vector of 100 elements and Func1 and Func2. In the single threaded version Func1 process vector elements and when Func1 finishes, Func2 must start a different process on elements. I'm curious to know if I utilize QtConcurrent::map in the following order, in which order actually Func1 and Func2 will execute?

QFuture<void> future;
future = QtConcurrent::map(vector, Func1);
future = QtConcurrent::map(vector, Func2);

I must mention that using future.waitForFinished() will block my application main thread which I don't want.

future = QtConcurrent::map(vector, Func1);
future.waitForFinished();
future = QtConcurrent::map(vector, Func2);

Also I don't want to execute those QtConcurrent::map in a secondary thread and do the future.waitForFinished() there, because in that approach I will lose one of my threads in threadpool. So, the question is do tasks added by QtConcurrent::map execute in order?

EDIT

In both single threaded and multi-threaded approaches Func2 must run only after Func1 finishes processing all elements.

Mohammad Rahimi
  • 965
  • 5
  • 15
  • Why do you need to preserve the execution order if you want to run two tasks concurrently? – vahancho Jun 16 '20 at 07:00
  • Can you clarify the precise sequencing you require. Do you require `Func1` to have operated on *all* elements of `vector` before `Func2` begins or (more likely) do you just require that `Func1` has operator on `vector[i]` before `Func2` operates on `vector[i]`. If it's the latter then just use a third function that calls `Func1` then `Func2` on the passed arg. – G.M. Jun 16 '20 at 07:29
  • @vahancho I don't want to run Func1 and Func2 simultaneously. I need Func1 to run on different elements of vector in concurrent fashion. Something like parallel `for` loops. @G.M. and I need Func1 finishes before Func2 starts. And thanks for responses. – Mohammad Rahimi Jun 16 '20 at 09:46
  • @G.M. yes. I think I have clarified it in Edit section of the question. thanks. – Mohammad Rahimi Jun 16 '20 at 09:59

2 Answers2

2

Since you want all calls to Func1 to complete before any calls to Func2 are made you can't make the second call to QtConcurrent::map before the first is known to have finished.

However, rather than calling future.waitForFinished() you can use a QFutureWatcher...

QFutureWatcher<void> watcher;
auto future = QtConcurrent::map(vector, Func1);
QObject::connect(&watcher, &QFutureWatcher::finished,
                 [&]()
                   {

                     /*
                      * All calls to Func1 have finished so it's
                      * safe to invoke Func2.
                      */
                     future = QtConcurrent::map(vector, Func2);
                   });
watcher.setFuture(future);

The above is untested but hopefully gives you some idea of what's required.

G.M.
  • 12,232
  • 2
  • 15
  • 18
  • Nice approach. totally works. I tested it. One problem though, I assumed more threads available will increase program speed, comparing my solution and yours, there was no visible difference on speed improvement. Any idea? My global instance has 8 threads one used for main application event loop and another for reading data. So for your approach there are 6 threads available and for mine 5 threads. I assume speed difference must be visible due to that 1 thread. I have a way in my code to observe vectors in a queue to be processed. – Mohammad Rahimi Jun 16 '20 at 11:31
  • I guess that I was using 6 threads not 5. I used `QtConcurrent::blockingMap` for my `Func1` which I guess `blockingMap` also uses the thread in which it is running and in my case 5+1 threads in total. In another word `QtConcurrent::blockingMap` is not equal to `QtConcurrent::map + future.waitForFinished()`. – Mohammad Rahimi Jun 16 '20 at 11:38
0

Sadly I wasn't able to find an answer from documentation so I have tested this code

future = QtConcurrent::map(vector, Func1);
future = QtConcurrent::map(vector, Func2);

and the result is that for some elements of the vector Func2 starts before Func1. Also there is no sequential order for processing vector elements which is natural using QtConcurrent::map.

For solving my problem I moved the Object with the slot that was calling both QtConcurrent::map to another thread and used wait which I will lose one thread in my threadpool.

Mohammad Rahimi
  • 965
  • 5
  • 15