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.

In this section