I wouldn’t do this while checking out a shared object.
I will most likely provide each thread object with a way to cancel execution inside its own thread, be it an event, a thread safety status variable, or something else.
The problem with the general controller of operations is that, from my point of view, the logic is canceled, why do you call it a “controller” when it does not control anything?
For me, the operation controller should receive a cancellation order, and then, in turn, select the appropriate flows and warn them about the termination. That would be the right “chain of commands" if you knew what I mean. The way you do this, you introduce unnatural behavior in a stream that does not “obey” orders to stop, and if it checks every time, if its “boss” “wrote the order”. Somehow it just doesn't seem right.
In addition, what if you are only one "some" of the threads to stop in the future? What if you want to enable some advanced logic so that threads stop setting the condition? Then you will have to rewrite the code in each thread to handle this condition.
Therefore, I will provide a way so that each thread can process signals to them, for example, using a Command Pattern with a FIFO structure.
(By the way, I understand that they are employees of the thread pool, and not the actual Thread classes, but still, I think every worker should be signaled in order to stop separately, and not vice versa).