45 #ifndef KOKKOS_FUTURE_HPP
46 #define KOKKOS_FUTURE_HPP
50 #include <Kokkos_Macros.hpp>
51 #if defined(KOKKOS_ENABLE_TASKDAG)
53 #include <Kokkos_Core_fwd.hpp>
54 #include <Kokkos_TaskScheduler_fwd.hpp>
57 #include <impl/Kokkos_TaskQueue.hpp>
58 #include <impl/Kokkos_TaskResult.hpp>
59 #include <impl/Kokkos_TaskBase.hpp>
62 #include <Kokkos_Concepts.hpp>
72 template <
typename ValueType,
typename ExecutionSpace,
typename QueueType>
73 class BasicFuture<ValueType, SimpleTaskScheduler<ExecutionSpace, QueueType>> {
75 using value_type = ValueType;
76 using execution_space = ExecutionSpace;
77 using scheduler_type = SimpleTaskScheduler<ExecutionSpace, QueueType>;
78 using queue_type =
typename scheduler_type::task_queue_type;
81 template <
class,
class>
82 friend class SimpleTaskScheduler;
83 template <
class,
class>
84 friend class BasicFuture;
86 using task_base_type =
typename scheduler_type::task_base_type;
87 using task_queue_type =
typename scheduler_type::task_queue_type;
89 using task_queue_traits =
typename scheduler_type::task_queue_traits;
90 using task_scheduling_info_type =
91 typename scheduler_type::task_scheduling_info_type;
93 using result_storage_type = Impl::TaskResultStorage<
95 Impl::SchedulingInfoStorage<Impl::RunnableTaskBase<task_queue_traits>,
96 task_scheduling_info_type>>;
98 OwningRawPtr<task_base_type> m_task =
nullptr;
100 KOKKOS_INLINE_FUNCTION
101 explicit BasicFuture(task_base_type* task) : m_task(task) {
108 KOKKOS_INLINE_FUNCTION
109 BasicFuture() noexcept : m_task(
nullptr) {}
111 KOKKOS_INLINE_FUNCTION
112 BasicFuture(BasicFuture&& rhs) noexcept : m_task(std::move(rhs.m_task)) {
113 rhs.m_task =
nullptr;
116 KOKKOS_INLINE_FUNCTION
117 BasicFuture(BasicFuture
const& rhs)
120 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
121 if (m_task) m_task->increment_reference_count();
124 KOKKOS_INLINE_FUNCTION
125 BasicFuture& operator=(BasicFuture&& rhs) noexcept {
126 if (m_task != rhs.m_task) {
129 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
135 rhs.m_task =
nullptr;
139 KOKKOS_INLINE_FUNCTION
140 BasicFuture& operator=(BasicFuture
const& rhs) {
141 if (m_task != rhs.m_task) {
144 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
146 if (m_task !=
nullptr) {
147 m_task->increment_reference_count();
154 template <
class T,
class S>
155 KOKKOS_INLINE_FUNCTION BasicFuture(
156 BasicFuture<T, S>&& rhs) noexcept
157 : m_task(std::move(rhs.m_task)) {
158 static_assert(std::is_same<scheduler_type, void>::value ||
159 std::is_same<scheduler_type, S>::value,
160 "Moved Futures must have the same scheduler");
162 static_assert(std::is_same<value_type, void>::value ||
163 std::is_same<value_type, T>::value,
164 "Moved Futures must have the same value_type");
167 rhs.m_task =
nullptr;
170 template <
class T,
class S>
171 KOKKOS_INLINE_FUNCTION BasicFuture(
172 BasicFuture<T, S>
const& rhs)
175 static_assert(std::is_same<scheduler_type, void>::value ||
176 std::is_same<scheduler_type, S>::value,
177 "Copied Futures must have the same scheduler");
179 static_assert(std::is_same<value_type, void>::value ||
180 std::is_same<value_type, T>::value,
181 "Copied Futures must have the same value_type");
183 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
184 if (m_task) m_task->increment_reference_count();
187 template <
class T,
class S>
188 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>
const& rhs) {
189 static_assert(std::is_same<scheduler_type, void>::value ||
190 std::is_same<scheduler_type, S>::value,
191 "Assigned Futures must have the same scheduler");
193 static_assert(std::is_same<value_type, void>::value ||
194 std::is_same<value_type, T>::value,
195 "Assigned Futures must have the same value_type");
197 if (m_task != rhs.m_task) {
200 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
201 if (m_task !=
nullptr) {
202 m_task->increment_reference_count();
208 template <
class T,
class S>
209 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>&& rhs) {
210 static_assert(std::is_same<scheduler_type, void>::value ||
211 std::is_same<scheduler_type, S>::value,
212 "Assigned Futures must have the same scheduler");
214 static_assert(std::is_same<value_type, void>::value ||
215 std::is_same<value_type, T>::value,
216 "Assigned Futures must have the same value_type");
218 if (m_task != rhs.m_task) {
221 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
227 rhs.m_task =
nullptr;
231 KOKKOS_INLINE_FUNCTION
232 ~BasicFuture() noexcept { clear(); }
236 KOKKOS_INLINE_FUNCTION
237 void clear() noexcept {
239 bool should_delete = m_task->decrement_and_check_reference_count();
241 static_cast<task_queue_type*
>(m_task->ready_queue_base_ptr())
242 ->deallocate(std::move(*m_task));
246 *
static_cast<task_base_type* volatile*
>(&m_task) =
nullptr;
249 KOKKOS_INLINE_FUNCTION
250 bool is_null() const noexcept {
return m_task ==
nullptr; }
252 KOKKOS_INLINE_FUNCTION
253 bool is_ready() const noexcept {
254 return (m_task ==
nullptr) || m_task->wait_queue_is_consumed();
257 KOKKOS_INLINE_FUNCTION
258 const typename Impl::TaskResult<ValueType>::reference_type
get()
const {
259 KOKKOS_EXPECTS(is_ready());
260 return static_cast<result_storage_type*
>(m_task)->value_reference();
269 template <
typename ValueType,
typename Scheduler>
272 template <
typename,
typename>
273 friend class BasicTaskScheduler;
274 template <
typename,
typename>
275 friend class BasicFuture;
276 friend class Impl::TaskBase;
277 template <
typename,
typename,
typename>
278 friend class Impl::Task;
285 using scheduler_type = Scheduler;
286 using queue_type =
typename scheduler_type::queue_type;
287 using execution_space =
typename scheduler_type::execution_space;
288 using value_type = ValueType;
295 using task_base = Impl::TaskBase;
299 KOKKOS_INLINE_FUNCTION
explicit BasicFuture(task_base* task)
301 if (task) queue_type::assign(&m_task, task);
309 KOKKOS_INLINE_FUNCTION
310 bool is_null()
const {
return nullptr == m_task; }
312 KOKKOS_INLINE_FUNCTION
313 int reference_count()
const {
314 return 0 != m_task ? m_task->reference_count() : 0;
319 KOKKOS_INLINE_FUNCTION
321 if (m_task) queue_type::assign(&m_task,
nullptr);
326 KOKKOS_INLINE_FUNCTION
327 ~BasicFuture() { clear(); }
331 KOKKOS_INLINE_FUNCTION
332 BasicFuture() noexcept : m_task(
nullptr) {}
334 KOKKOS_INLINE_FUNCTION
335 BasicFuture(BasicFuture&& rhs) noexcept : m_task(rhs.m_task) {
336 rhs.m_task =
nullptr;
339 KOKKOS_INLINE_FUNCTION
340 BasicFuture(
const BasicFuture& rhs) : m_task(nullptr) {
341 if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
344 KOKKOS_INLINE_FUNCTION
345 BasicFuture& operator=(BasicFuture&& rhs) noexcept {
348 rhs.m_task =
nullptr;
352 KOKKOS_INLINE_FUNCTION
353 BasicFuture& operator=(BasicFuture
const& rhs) {
354 if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
360 template <
class T,
class S>
361 KOKKOS_INLINE_FUNCTION BasicFuture(
362 BasicFuture<T, S>&& rhs) noexcept
363 : m_task(rhs.m_task) {
364 static_assert(std::is_same<scheduler_type, void>::value ||
365 std::is_same<scheduler_type, S>::value,
366 "Assigned Futures must have the same scheduler");
368 static_assert(std::is_same<value_type, void>::value ||
369 std::is_same<value_type, T>::value,
370 "Assigned Futures must have the same value_type");
375 template <
class T,
class S>
376 KOKKOS_INLINE_FUNCTION BasicFuture(
377 BasicFuture<T, S>
const& rhs)
379 static_assert(std::is_same<scheduler_type, void>::value ||
380 std::is_same<scheduler_type, S>::value,
381 "Assigned Futures must have the same scheduler");
383 static_assert(std::is_same<value_type, void>::value ||
384 std::is_same<value_type, T>::value,
385 "Assigned Futures must have the same value_type");
387 if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
390 template <
class T,
class S>
391 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>
const& rhs) {
392 static_assert(std::is_same<scheduler_type, void>::value ||
393 std::is_same<scheduler_type, S>::value,
394 "Assigned Futures must have the same scheduler");
396 static_assert(std::is_same<value_type, void>::value ||
397 std::is_same<value_type, T>::value,
398 "Assigned Futures must have the same value_type");
400 if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
404 template <
class T,
class S>
405 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>&& rhs) {
406 static_assert(std::is_same<scheduler_type, void>::value ||
407 std::is_same<scheduler_type, S>::value,
408 "Assigned Futures must have the same scheduler");
410 static_assert(std::is_same<value_type, void>::value ||
411 std::is_same<value_type, T>::value,
412 "Assigned Futures must have the same value_type");
422 KOKKOS_INLINE_FUNCTION
423 int is_ready() const noexcept {
424 return (
nullptr == m_task) ||
425 (((task_base*)task_base::LockTag) == m_task->m_wait);
428 KOKKOS_INLINE_FUNCTION
429 const typename Impl::TaskResult<ValueType>::reference_type
get()
const {
430 if (
nullptr == m_task) {
431 Kokkos::abort(
"Kokkos:::Future::get ERROR: is_null()");
433 return Impl::TaskResult<ValueType>::get(m_task);
438 template <
typename,
typename ExecSpace =
void>
439 struct is_future :
public std::false_type {};
441 template <
typename ValueType,
typename Scheduler,
typename ExecSpace>
442 struct is_future<BasicFuture<ValueType, Scheduler>, ExecSpace>
443 : std::integral_constant<
445 std::is_same<ExecSpace, typename Scheduler::execution_space>::value ||
446 std::is_void<ExecSpace>::value> {};
454 template <
class Arg1,
class Arg2>
455 class ResolveFutureArgOrder {
457 enum { Arg1_is_space = Kokkos::is_space<Arg1>::value };
458 enum { Arg2_is_space = Kokkos::is_space<Arg2>::value };
459 enum { Arg1_is_value = !Arg1_is_space && !std::is_same<Arg1, void>::value };
460 enum { Arg2_is_value = !Arg2_is_space && !std::is_same<Arg2, void>::value };
462 static_assert(!(Arg1_is_space && Arg2_is_space),
463 "Future cannot be given two spaces");
465 static_assert(!(Arg1_is_value && Arg2_is_value),
466 "Future cannot be given two value types");
468 using value_type =
typename std::conditional<
470 typename std::conditional<Arg2_is_value, Arg2, void>::type>::type;
472 using execution_space =
typename std::conditional<
474 typename std::conditional<Arg2_is_space, Arg2,
475 void>::type>::type::execution_space;
478 using type = BasicFuture<value_type, TaskScheduler<execution_space>>;
490 template <
class Arg1 =
void,
class Arg2 =
void>
491 using Future =
typename Impl::ResolveFutureArgOrder<Arg1, Arg2>::type;
bool is_null(const boost::shared_ptr< T > &p)