vtkThreadedCallbackQueue: last touches
This MR makes the following changes to vtkThreadedCallbackQueue
:
- Storing the args as native type of the arguments of function f when relevant
- The arguments are now stored in the type expected by the function f when the argument expected by f is an lvalue referencee. In such circumstances, this allows to store a copy in the type expected by f seamlessly.
- Removing Start and Stop from public API
- This API can be dangerous because the user could call
Wait()
on a token an end up in a deadlock ifStop()
was called anywhere.Stop
andStart
are now private. - There also was a bug in
SetNumberOfThreads
: the thread id was not instantiated correctly when resizing the threads when the queue was already running.
- This API can be dangerous because the user could call
- Removing Stop API
- Since the queue is started at construction and cannot be stopped, there
is no need to keep this API. This also lightens the code a bit because
we can remove
IsRunning
- Since the queue is started at construction and cannot be stopped, there
is no need to keep this API. This also lightens the code a bit because
we can remove
- Optimize
PushDependent
-
PushDependent
used to push a function just waiting on all input tokens before executing. This is wasteful for the thread waiting. - To make things smoother, we instroduce a shared state between an invoker
an its token (called
InvokerTokenSharedState
). When a function needs to wait on a token, it notifies its associated invoker that it is waiting for it to finish by inserting the function's new token inDependentTokens
in the shared state of the invoker it's waiting on. If there are any invokers we need to wait on that is not finished, the new invoker is pushed inside a waiting list calledInvokersOnHold
. - On the invoker side, when it has finished, it goes through all its
DependentTokens
. It fetches the shared state of each token, and looks at the counterNumberOfPriorTokensRemaining
which has been incremented for each unfinished token this token found in its token list. The invoker decrements this counter, and when the counter reaches 0, it means that the current invoker is the last invoker this token was waiting on. So the invoker can move this token's invoker in the running queue. We put it on the front as this invoker's execution already has been delayed.
-
- Replacing
Token
bySharedFuture
- Having a
std::shared_future
instance made that independent locks were done when they could have been combined. ThevtkCallbackToken
was actually already near to have all the functionalities of astd::shared_future
. - We also wanted to avoid
std::shared_future::wait_for(0)
, as this call blocks the current thread. In our implementation, if the invoker is not done yet, you can call an equivalent ofwait_for(0)
asIsReady
without actually blocking the thread.
- Having a
- Adding
vtkThreadedCallbackQueue::Wait
API- The new
Wait
function takes a container of shared futures as input. It is in general less ressource consuming than callingWait
on each shared future as it can block at most once.
- The new
- Specializing
std::hash<vtkSmartPointer<T>>
to allow to create hash maps of smart pointers
Edited by Yohann Bearzi (Kitware)