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
20class WorkDispatcher;
21
40{
41public:
42
43 WorkSingularTask(WorkSingularTask const &) = delete;
44 WorkSingularTask &operator=(WorkSingularTask const &) = delete;
45
46#ifdef doxygen
47
56 template <class Callable, class A1, class A2, ... class AN>
58 Callable &&c, A1 &&a1, A2 &&a2, ... AN &&aN);
59
60#else // doxygen
61
62 template <class Callable, class... Args>
63 WorkSingularTask(WorkDispatcher &d, Callable &&c, Args&&... args)
64 : _waker(_MakeWaker(d, std::bind(std::forward<Callable>(c),
65 std::forward<Args>(args)...)))
66 , _count(0) {}
67
68#endif // doxygen
69
73 inline void Wake() {
74 if (++_count == 1)
75 _waker(_count);
76 }
77
78private:
79 template <class Dispatcher, class Fn>
80 struct _Waker {
81 explicit _Waker(Dispatcher &d, Fn &&fn)
82 : _dispatcher(d), _fn(std::move(fn)) {}
83
84 void operator()(std::atomic_size_t &count) const {
85 _dispatcher.Run(
86 [this, &count]() {
87 // We read the current refCount into oldCount, then we
88 // invoke the task function. Finally we try to CAS the
89 // refCount to zero. If we fail, it means some other
90 // clients have invoked Wake() in the meantime. In that
91 // case we go again to ensure the task can do whatever it
92 // was awakened to do. Once we successfully take the count
93 // to zero, we stop.
94 std::size_t old = count;
95 do { _fn(); } while (
96 !count.compare_exchange_strong(old, 0));
97 });
98 }
99 Dispatcher &_dispatcher;
100 Fn _fn;
101 };
102
103 template <class Dispatcher, class Fn>
104 static std::function<void (std::atomic_size_t &)>
105 _MakeWaker(Dispatcher &d, Fn &&fn) {
106 return std::function<void (std::atomic_size_t &)>(
107 _Waker<Dispatcher, typename std::decay<Fn>::type>(
108 d, std::forward<Fn>(fn)));
109 }
110
111 std::function<void (std::atomic_size_t &)> _waker;
112 std::atomic_size_t _count;
113};
114
115PXR_NAMESPACE_CLOSE_SCOPE
116
117#endif // PXR_BASE_WORK_SINGULAR_TASK_H
A work dispatcher runs concurrent tasks.
Definition: dispatcher.h:176
A WorkSingularTask runs a task in a WorkDispatcher, but never concurrently with itself.
Definition: singularTask.h:40
void Wake()
Ensure that this task runs at least once after this call.
Definition: singularTask.h:73
WorkSingularTask(WorkDispatcher &dispatcher, Callable &&c, A1 &&a1, A2 &&a2,... AN &&aN)
Create a singular task to be run in dispatcher.
STL namespace.