44 #ifndef KOKKOS_FUTURE_HPP
45 #define KOKKOS_FUTURE_HPP
49 #include <Kokkos_Macros.hpp>
50 #if defined( KOKKOS_ENABLE_TASKDAG )
52 #include <Kokkos_Core_fwd.hpp>
53 #include <Kokkos_TaskScheduler_fwd.hpp>
56 #include <impl/Kokkos_TaskQueue.hpp>
57 #include <impl/Kokkos_TaskResult.hpp>
58 #include <impl/Kokkos_TaskBase.hpp>
61 #include <Kokkos_Concepts.hpp>
70 template <
typename ValueType,
typename ExecutionSpace,
typename QueueType>
71 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;
83 template <
class,
class>
84 friend class SimpleTaskScheduler;
85 template <
class,
class>
86 friend class BasicFuture;
88 using task_base_type =
typename scheduler_type::task_base_type;
89 using task_queue_type =
typename scheduler_type::task_queue_type;
91 using task_queue_traits =
typename scheduler_type::task_queue_traits;
92 using task_scheduling_info_type =
typename scheduler_type::task_scheduling_info_type;
94 using result_storage_type =
95 Impl::TaskResultStorage<
97 Impl::SchedulingInfoStorage<
98 Impl::RunnableTaskBase<task_queue_traits>,
99 task_scheduling_info_type
105 OwningRawPtr<task_base_type> m_task =
nullptr;
107 KOKKOS_INLINE_FUNCTION
109 BasicFuture(task_base_type* task)
118 KOKKOS_INLINE_FUNCTION
119 BasicFuture() noexcept : m_task(
nullptr) { }
121 KOKKOS_INLINE_FUNCTION
122 BasicFuture(BasicFuture&& rhs) noexcept
123 : m_task(std::move(rhs.m_task))
125 rhs.m_task =
nullptr;
128 KOKKOS_INLINE_FUNCTION
129 BasicFuture(BasicFuture
const& rhs)
133 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
134 if(m_task) m_task->increment_reference_count();
137 KOKKOS_INLINE_FUNCTION
138 BasicFuture& operator=(BasicFuture&& rhs) noexcept
140 if(m_task != rhs.m_task) {
143 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
150 rhs.m_task =
nullptr;
154 KOKKOS_INLINE_FUNCTION
155 BasicFuture& operator=(BasicFuture
const& rhs)
157 if(m_task != rhs.m_task) {
160 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
162 if(m_task !=
nullptr) { m_task->increment_reference_count(); }
168 template <
class T,
class S>
169 KOKKOS_INLINE_FUNCTION
170 BasicFuture(BasicFuture<T, S>&& rhs) noexcept
171 : m_task(std::move(rhs.m_task))
174 std::is_same<scheduler_type, void>::value ||
175 std::is_same<scheduler_type, S>::value,
176 "Moved Futures must have the same scheduler"
180 std::is_same<value_type, void>::value ||
181 std::is_same<value_type, T>::value,
182 "Moved Futures must have the same value_type"
186 rhs.m_task =
nullptr;
189 template <
class T,
class S>
190 KOKKOS_INLINE_FUNCTION
191 BasicFuture(BasicFuture<T, S>
const& rhs)
196 std::is_same<scheduler_type, void>::value ||
197 std::is_same<scheduler_type, S>::value,
198 "Copied Futures must have the same scheduler"
202 std::is_same<value_type, void>::value ||
203 std::is_same<value_type, T>::value,
204 "Copied Futures must have the same value_type"
207 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
208 if(m_task) m_task->increment_reference_count();
211 template <
class T,
class S>
212 KOKKOS_INLINE_FUNCTION
214 operator=(BasicFuture<T, S>
const& rhs)
217 std::is_same<scheduler_type, void>::value ||
218 std::is_same<scheduler_type, S>::value,
219 "Assigned Futures must have the same scheduler"
223 std::is_same<value_type, void>::value ||
224 std::is_same<value_type, T>::value,
225 "Assigned Futures must have the same value_type"
228 if(m_task != rhs.m_task) {
231 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
232 if(m_task !=
nullptr) { m_task->increment_reference_count(); }
237 template<
class T,
class S>
238 KOKKOS_INLINE_FUNCTION
239 BasicFuture& operator=(BasicFuture<T, S>&& rhs)
242 std::is_same<scheduler_type, void>::value ||
243 std::is_same<scheduler_type, S>::value,
244 "Assigned Futures must have the same scheduler"
248 std::is_same<value_type, void>::value ||
249 std::is_same<value_type, T>::value,
250 "Assigned Futures must have the same value_type"
253 if(m_task != rhs.m_task) {
256 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
263 rhs.m_task =
nullptr;
267 KOKKOS_INLINE_FUNCTION
268 ~BasicFuture() noexcept { clear(); }
272 KOKKOS_INLINE_FUNCTION
273 void clear() noexcept {
275 bool should_delete = m_task->decrement_and_check_reference_count();
277 static_cast<task_queue_type*
>(m_task->ready_queue_base_ptr())
278 ->deallocate(std::move(*m_task));
282 *
static_cast<task_base_type* volatile*
>(&m_task) =
nullptr;
285 KOKKOS_INLINE_FUNCTION
286 bool is_null() const noexcept {
287 return m_task ==
nullptr;
291 KOKKOS_INLINE_FUNCTION
292 bool is_ready() const noexcept {
293 return (m_task ==
nullptr) || m_task->wait_queue_is_consumed();
296 KOKKOS_INLINE_FUNCTION
297 const typename Impl::TaskResult< ValueType >::reference_type
300 KOKKOS_EXPECTS(is_ready());
301 return static_cast<result_storage_type*
>(m_task)->value_reference();
311 template <
typename ValueType,
typename Scheduler>
315 template<
typename ,
typename >
friend class BasicTaskScheduler ;
316 template<
typename ,
typename >
friend class BasicFuture ;
317 friend class Impl::TaskBase ;
318 template<
typename ,
typename ,
typename >
friend class Impl::Task ;
327 using scheduler_type = Scheduler;
328 using queue_type =
typename scheduler_type::queue_type;
329 using execution_space =
typename scheduler_type::execution_space;
330 using value_type = ValueType;
338 using task_base = Impl::TaskBase;
342 KOKKOS_INLINE_FUNCTION
explicit
343 BasicFuture( task_base * task ) : m_task(0)
344 {
if ( task ) queue_type::assign( & m_task , task ); }
352 KOKKOS_INLINE_FUNCTION
353 bool is_null()
const {
return 0 == m_task ; }
355 KOKKOS_INLINE_FUNCTION
356 int reference_count()
const
357 {
return 0 != m_task ? m_task->reference_count() : 0 ; }
361 KOKKOS_INLINE_FUNCTION
363 {
if ( m_task ) queue_type::assign( & m_task , (task_base*)0 ); }
367 KOKKOS_INLINE_FUNCTION
368 ~BasicFuture() { clear(); }
372 KOKKOS_INLINE_FUNCTION
373 BasicFuture() noexcept : m_task(
nullptr) { }
375 KOKKOS_INLINE_FUNCTION
376 BasicFuture( BasicFuture && rhs ) noexcept
377 : m_task( rhs.m_task )
382 KOKKOS_INLINE_FUNCTION
383 BasicFuture(
const BasicFuture & rhs )
385 {
if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); }
387 KOKKOS_INLINE_FUNCTION
388 BasicFuture& operator=(BasicFuture&& rhs) noexcept
391 m_task = rhs.m_task ;
396 KOKKOS_INLINE_FUNCTION
397 BasicFuture& operator=(BasicFuture
const& rhs)
399 if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task );
405 template <
class T,
class S>
406 KOKKOS_INLINE_FUNCTION
407 BasicFuture(BasicFuture<T, S>&& rhs) noexcept
408 : m_task( rhs.m_task )
411 ( std::is_same<scheduler_type, void>::value ||
412 std::is_same<scheduler_type, S>::value
413 ,
"Assigned Futures must have the same scheduler" );
416 ( std::is_same< value_type , void >::value ||
417 std::is_same<value_type, T>::value
418 ,
"Assigned Futures must have the same value_type" );
423 template <
class T,
class S>
424 KOKKOS_INLINE_FUNCTION
425 BasicFuture(BasicFuture<T, S>
const& rhs)
429 ( std::is_same<scheduler_type, void>::value ||
430 std::is_same<scheduler_type, S>::value
431 ,
"Assigned Futures must have the same scheduler" );
434 ( std::is_same< value_type , void >::value ||
435 std::is_same<value_type, T>::value
436 ,
"Assigned Futures must have the same value_type" );
438 if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task );
441 template <
class T,
class S>
442 KOKKOS_INLINE_FUNCTION
444 operator=(BasicFuture<T, S>
const& rhs)
447 ( std::is_same<scheduler_type, void>::value ||
448 std::is_same<scheduler_type, S>::value
449 ,
"Assigned Futures must have the same scheduler" );
452 ( std::is_same< value_type , void >::value ||
453 std::is_same<value_type, T>::value
454 ,
"Assigned Futures must have the same value_type" );
456 if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task );
460 template<
class T,
class S>
461 KOKKOS_INLINE_FUNCTION
462 BasicFuture& operator=(BasicFuture<T, S>&& rhs)
465 ( std::is_same<scheduler_type, void>::value ||
466 std::is_same<scheduler_type, S>::value
467 ,
"Assigned Futures must have the same scheduler" );
470 ( std::is_same< value_type , void >::value ||
471 std::is_same<value_type, T>::value
472 ,
"Assigned Futures must have the same value_type" );
475 m_task = rhs.m_task ;
482 KOKKOS_INLINE_FUNCTION
483 int is_ready() const noexcept
484 {
return ( 0 == m_task ) || ( ((task_base*) task_base::LockTag) == m_task->m_wait ); }
486 KOKKOS_INLINE_FUNCTION
487 const typename Impl::TaskResult< ValueType >::reference_type
491 Kokkos::abort(
"Kokkos:::Future::get ERROR: is_null()");
493 return Impl::TaskResult< ValueType >::get( m_task );
498 template<
typename ,
typename ExecSpace =
void >
499 struct is_future :
public std::false_type {};
501 template<
typename ValueType,
typename Scheduler,
typename ExecSpace>
502 struct is_future<BasicFuture<ValueType, Scheduler>, ExecSpace>
503 : std::integral_constant<bool,
504 std::is_same<ExecSpace, typename Scheduler::execution_space>::value
505 || std::is_void<ExecSpace>::value
515 template <
class Arg1,
class Arg2>
516 class ResolveFutureArgOrder {
518 enum { Arg1_is_space = Kokkos::is_space<Arg1>::value };
519 enum { Arg2_is_space = Kokkos::is_space<Arg2>::value };
520 enum { Arg1_is_value = !Arg1_is_space && !std::is_same<Arg1, void>::value };
521 enum { Arg2_is_value = !Arg2_is_space && !std::is_same<Arg2, void>::value };
524 ! ( Arg1_is_space && Arg2_is_space ),
525 "Future cannot be given two spaces"
529 ! ( Arg1_is_value && Arg2_is_value ),
530 "Future cannot be given two value types"
534 typename std::conditional<Arg1_is_value, Arg1,
535 typename std::conditional<Arg2_is_value, Arg2, void>::type
538 using execution_space =
539 typename std::conditional<Arg1_is_space, Arg1,
540 typename std::conditional<Arg2_is_space, Arg2, void>::type
541 >::type::execution_space;
545 using type = BasicFuture<value_type, TaskScheduler<execution_space>>;
558 template <
class Arg1 =
void,
class Arg2 =
void>
559 using Future =
typename Impl::ResolveFutureArgOrder<Arg1, Arg2>::type;
bool is_null(const boost::shared_ptr< T > &p)