HDK
|
#include "pxr/pxr.h"
#include "pxr/base/work/api.h"
#include "pxr/base/work/dispatcher.h"
#include "pxr/base/tf/pyLock.h"
#include <tbb/task_arena.h>
#include <utility>
Go to the source code of this file.
Functions | |
template<class Fn > | |
PXR_NAMESPACE_OPEN_SCOPE auto | WorkWithScopedParallelism (Fn &&fn, bool dropPythonGIL=true) |
template<class Fn > | |
auto | WorkWithScopedDispatcher (Fn &&fn, bool dropPythonGIL=true) |
auto WorkWithScopedDispatcher | ( | Fn && | fn, |
bool | dropPythonGIL = true |
||
) |
Similar to WorkWithScopedParallelism(), but pass a WorkDispatcher instance to fn
for its use during the scoped parallelism. Accordingly, fn
must accept a WorkDispatcher lvalue reference argument. After fn
returns but before the scoped parallelism ends, call WorkDispatcher::Wait() on the dispatcher instance. The dropPythonGIL
argument has the same meaning as it does for WorkWithScopedParallelism().
Definition at line 119 of file withScopedParallelism.h.
PXR_NAMESPACE_OPEN_SCOPE auto WorkWithScopedParallelism | ( | Fn && | fn, |
bool | dropPythonGIL = true |
||
) |
Invoke fn
, ensuring that all wait operations on concurrent constructs invoked by the calling thread only take tasks created within the scope of fn
's execution.
Ordinarily when a thread invokes a wait operation on a concurrent construct (e.g. the explicit WorkDispatcher::Wait(), or the implicit wait in loops like WorkParallelForEach()) it joins the pool of worker threads and executes tasks to help complete the work. This is good, since the calling thread does useful work instead of busy waiting or sleeping until the work has completed. However, this can be problematic depending on the calling context, and which tasks the waiting thread executes.
For example, consider the following example: a demand-populated resource cache.
Here when a caller has requested the resource for key
for the first time, we do the work to populate the resource while holding a lock on that resource entry in the cache. The problem is that when the calling thread waits for work to complete, if it picks up tasks unrelated to this context and those tasks attempt to call GetResource() with the same key, the process will deadlock.
This can be fixed by using WorkWithScopedParallelism() to ensure that the calling thread's wait operations only take tasks that were created during the scope of the population work:
This limits parallelism by only a small degree. It's only the waiting thread that restricts the tasks it can take to the protected scope: all other worker threads continue unhindered.
If Python support is enabled and dropPythonGIL
is true, this function ensures the GIL is released before invoking fn
. If this function released the GIL, it reacquires it before returning.
Definition at line 100 of file withScopedParallelism.h.