QProcessDialog with multiple QFutureWatchers

I would need assistance for multi-threading a function. Imagine you had a class Data, and its object data. You have names of files in vector of strings data.names, and their content in a map data.content. Now, there is a function doProcessThread, that should be run in each spawned thread, while proper arguments are passed (int, Data, vector). The function modifies the content of the data (each thread modifies one element of the map). I wrote the code and it does the job just fine. However, reporting back to the QProcessDialog is not correct. As you see in the code below, I am generating multiple QFutureWatcher objects (pointers actually), and connecting all of them with a dialog. As you may guess, the dialog closes with the first finished thread, even though others are still running. If I place it after the loop for waitForFinished, it will never go away on its own. Also, if I press cancel on the dialog, it ignores. It is not showing any percentage or incrementing. Could you give me some pointers what would be the best way to address this? Thank you.

This type of task is better handled by QtConcurrent::map than multiple calls to QtConcurrent::run. With map you get a single future with progress indication. With run you'd need to handle that manually but why re-invent the wheel?
To use map, if possible, convert your Data structure to more processing friendly form i.e. a single container of stuff instead of stuff of two containers.
That would be great but if that's not possible for some reason you can create a lightweight "adapter" struct like this:

struct Params {
const QString* fileName; //pointing to an element in the data.names container
WhateverContent* content; //pointing to an element in the data.content container
Output* output; //pointing to an element in someVector
};

and then adapt your Processer::doProcessThread to take that as a single parameter.

Other comments:

Consider switching to the new connect syntax (a lot less error prone).

Mind your object ownership. You are leaking all the QFutureWatcher instances. Either give them parents or delete them manually. Better yet use map and create only one on the stack.

Don't reset when you mean close. Result is the same in this case but it's better to explicitly state the intent.

So a skeleton code for this (may have bugs, flows out of my head ;) ):

Thanks a lot for your reply, I really appreciate all your comments and help!
My Data class cannot really be converted into a container of any sort, that is why I kept using QtConcurrent::run (I could feed it with the whole object). Can QtConcurrent::map use QMap for iteration?

I followed your suggestions carefully and created an "adapter" struct, and re-defined doProcessThread function (so that it takes a reference to that struct). I used QVector to store instances of that struct, placed the vector as a first parameter in ::map, but I got an error of not matching for call to ‘(QtConcurrent::MemberFunctionWrapper1<void... I looked it up, and tried with lambda expression, but got another error: undefined reference to `QtConcurrent::ThreadEngineBase::~ThreadEngineBase().

In the end, I decided not to complicate it further, but to think of a better design for my containers and the functions that modify them. I will get back to this post once I try it again. I will need to re-organize all my functions and variables so that I can use multi-threading in such a way.

Can QtConcurrent::map use QMap for iteration?
It can use any iterator based container. The gotcha with QMap is that, unlike in std::map, its iterator's operator* returns a reference to the value, so there's no way to get to the key this way. So if you used a map like QMap<String, Stuff> you would get Stuff& parameter in the map call with no way to get to the string.
In contrast, the std::map's iterator is a pair of key/value, so with std::map<QString, Stuff> you would get a std::pair<QString, Stuff>& parameter in the map call.