InFlightJobs
Counts the jobs an object has in flight, so its destructor can wait for exactly those.
In the namespace utility::concurrent. Declared in src/libs/libutil/utility/concurrent/InFlightJobs.hpp.
Detailed description
The shape this exists for: `(void)QtConcurrent::run(pool, [this, …]() {…})` — the future discarded, the job detached, the lambda holding `this` and whatever raw pointers came with it. Nothing waits, so an owner destroyed while a job runs leaves the job writing into freed memory. It presents as an intermittent crash AFTER a suite reports every case passed, and the crash site is often inside a correctly locked container, because the lock was freed along with its owner.
A pool the object owns can be drained in its destructor (three construct workers do exactly that). A SHARED pool cannot: waiting on it waits for every unrelated job in the process. This counts only the owner's own jobs, on whichever pool they run:
(void)QtConcurrent::run(sharedPool(), mInFlight.track([this]() { … }));
…
Owner::~Owner() { mInFlight.waitForDone(); } // FIRST line
`track()` counts the job at submission, not at start, so a job queued but not yet running is waited for too. Call `waitForDone()` as the destructor's first statement: the members the jobs touch are destroyed after the body, but the body is the last point at which ALL of them are still alive.