// @(#)root/thread:$Id$ // Author: Danilo Piparo August 2017 /************************************************************************* * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #ifndef ROOT_TFuture #define ROOT_TFuture #include "RConfigure.h" #include "ROOT/TTaskGroup.hxx" #include #include // exclude in case ROOT does not have IMT support #ifndef R__USE_IMT // No need to error out for dictionaries. #if !defined(__ROOTCLING__) && !defined(G__DICTIONARY) #error "Cannot use ROOT::Experimental::Async without defining R__USE_IMT." #endif #else namespace ROOT { // fwd declaration namespace Experimental { template class TFuture; } namespace Detail { template class TFutureImpl { template friend class Experimental::TFuture; protected: using TTaskGroup = Experimental::TTaskGroup; std::future fStdFut; std::unique_ptr fTg{nullptr}; TFutureImpl(std::future &&fut, std::unique_ptr &&tg) : fStdFut(std::move(fut)) { fTg = std::move(tg); }; TFutureImpl(){}; TFutureImpl(std::future &&fut) : fStdFut(std::move(fut)) {} TFutureImpl(TFutureImpl &&other) : fStdFut(std::move(other.fStdFut)), fTg(std::move(other.fTg)) {} TFutureImpl &operator=(std::future &&other) { fStdFut = std::move(other); } TFutureImpl &operator=(TFutureImpl &&other) = default; public: TFutureImpl &operator=(TFutureImpl &other) = delete; TFutureImpl(const TFutureImpl &other) = delete; void wait() { if (fTg) fTg->Wait(); } bool valid() const { return fStdFut.valid(); }; }; } namespace Experimental { //////////////////////////////////////////////////////////////////////////////// /// A TFuture class. It can wrap an std::future. template class TFuture final : public ROOT::Detail::TFutureImpl { template friend TFuture< typename std::result_of::type(typename std::decay::type...)>::type> Async(Function &&f, Args &&... args); private: TFuture(std::future &&fut, std::unique_ptr &&tg) : ROOT::Detail::TFutureImpl(std::forward>(fut), std::move(tg)){}; public: TFuture(std::future &&fut) : ROOT::Detail::TFutureImpl(std::forward>(fut)){}; T get() { this->wait(); return this->fStdFut.get(); } }; /// \cond // Two specialisations, for void and T& as for std::future template <> class TFuture final : public ROOT::Detail::TFutureImpl { template friend TFuture< typename std::result_of::type(typename std::decay::type...)>::type> Async(Function &&f, Args &&... args); private: TFuture(std::future &&fut, std::unique_ptr &&tg) : ROOT::Detail::TFutureImpl(std::forward>(fut), std::move(tg)){}; public: TFuture(std::future &&fut) : ROOT::Detail::TFutureImpl(std::forward>(fut)){}; void get() { this->wait(); fStdFut.get(); } }; template class TFuture final : public ROOT::Detail::TFutureImpl { template friend TFuture< typename std::result_of::type(typename std::decay::type...)>::type> Async(Function &&f, Args &&... args); private: TFuture(std::future &&fut, std::unique_ptr &&tg) : ROOT::Detail::TFutureImpl(std::forward>(fut), std::move(tg)){}; public: TFuture(std::future &&fut) : ROOT::Detail::TFutureImpl(std::forward>(fut)){}; T &get() { this->wait(); return this->fStdFut.get(); } }; /// \endcond //////////////////////////////////////////////////////////////////////////////// /// Runs a function asynchronously potentially in a new thread and returns a /// ROOT TFuture that will hold the result. template TFuture::type(typename std::decay::type...)>::type> Async(Function &&f, Args &&... args) { // The return type according to the standard implementation of std::future // the long type is due to the fact that we want to be c++11 compatible. // A more elegant version would be: // std::future(std::decay_t...)>> using Ret_t = typename std::result_of::type(typename std::decay::type...)>::type; auto thisPt = std::make_shared>(std::bind(f, args...)); std::unique_ptr tg(new ROOT::Experimental::TTaskGroup()); tg->Run([thisPt]() { (*thisPt)(); }); return ROOT::Experimental::TFuture(thisPt->get_future(), std::move(tg)); } } } #endif #endif