Loading...
Searching...
No Matches
singularTask.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_WORK_SINGULAR_TASK_H
8#define PXR_BASE_WORK_SINGULAR_TASK_H
9
11
12#include "pxr/pxr.h"
13
14#include <atomic>
15#include <functional>
16#include <type_traits>
17
18PXR_NAMESPACE_OPEN_SCOPE
19
38{
39public:
40
41 WorkSingularTask(WorkSingularTask const &) = delete;
42 WorkSingularTask &operator=(WorkSingularTask const &) = delete;
43
44#ifdef doxygen
45
57 template <class Dispatcher, class Callable, class A1, class A2, ... class AN>
58 WorkSingularTask(Dispatcher &dispatcher,
59 Callable &&c, A1 &&a1, A2 &&a2, ... AN &&aN);
60
61#else // doxygen
62
63 template <class Dispatcher, class Callable, class... Args>
64 WorkSingularTask(Dispatcher &d, Callable &&c, Args&&... args)
65 : _waker(_MakeWaker(d, std::bind(std::forward<Callable>(c),
66 std::forward<Args>(args)...)))
67 , _count(0) {}
68
69#endif // doxygen
70
74 inline void Wake() {
75 if (++_count == 1)
76 _waker(_count);
77 }
78
79private:
80 template <class Dispatcher, class Fn>
81 struct _Waker {
82 explicit _Waker(Dispatcher &d, Fn &&fn)
83 : _dispatcher(d), _fn(std::move(fn)) {}
84
85 void operator()(std::atomic_size_t &count) const {
86 _dispatcher.Run(
87 [this, &count]() {
88 // We read the current refCount into oldCount, then we
89 // invoke the task function. Finally we try to CAS the
90 // refCount to zero. If we fail, it means some other
91 // clients have invoked Wake() in the meantime. In that
92 // case we go again to ensure the task can do whatever it
93 // was awakened to do. Once we successfully take the count
94 // to zero, we stop.
95 std::size_t old = count;
96 do { _fn(); } while (
97 !count.compare_exchange_strong(old, 0));
98 });
99 }
100 Dispatcher &_dispatcher;
101 Fn _fn;
102 };
103
104 template <class Dispatcher, class Fn>
105 static std::function<void (std::atomic_size_t &)>
106 _MakeWaker(Dispatcher &d, Fn &&fn) {
107 return std::function<void (std::atomic_size_t &)>(
108 _Waker<Dispatcher, typename std::decay<Fn>::type>(
109 d, std::forward<Fn>(fn)));
110 }
111
112 std::function<void (std::atomic_size_t &)> _waker;
113 std::atomic_size_t _count;
114};
115
116PXR_NAMESPACE_CLOSE_SCOPE
117
118#endif // PXR_BASE_WORK_SINGULAR_TASK_H
A WorkSingularTask runs a task in a work dispatcher, but never concurrently with itself.
void Wake()
Ensure that this task runs at least once after this call.
WorkSingularTask(Dispatcher &dispatcher, Callable &&c, A1 &&a1, A2 &&a2,... AN &&aN)
Create a singular task to be run in dispatcher.
STL namespace.