X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/94a6ea22dbd2f12d1015925d3c3fe7a95b38d2e3..e79c652187a77f7383b81afb91a4adc8d38986ef:/include/simgrid/s4u/actor.hpp diff --git a/include/simgrid/s4u/actor.hpp b/include/simgrid/s4u/actor.hpp index 24728db6a9..5039f84983 100644 --- a/include/simgrid/s4u/actor.hpp +++ b/include/simgrid/s4u/actor.hpp @@ -6,17 +6,29 @@ #ifndef SIMGRID_S4U_ACTOR_HPP #define SIMGRID_S4U_ACTOR_HPP +#include +#include +#include +#include #include +#include +#include +#include +#include + +#include + #include +#include + +#include #include #include namespace simgrid { namespace s4u { -/** @addtogroup s4u_actor - * - * @tableofcontents +/** @ingroup s4u_api * * An actor is an independent stream of execution in your distributed application. * @@ -32,8 +44,6 @@ namespace s4u { * of this standard may help to understand the philosophy of the S4U * Actors. * - * (back to the @ref s4u_api "S4U documentation") - * * @section s4u_actor_def Defining the skeleton of an Actor * * %As in the C++11 @@ -41,6 +51,8 @@ namespace s4u { * pure function or as an object. It is very simple with functions: * * @code{.cpp} + * #include "s4u/actor.hpp" + * * // Declare the code of your worker * void worker() { * printf("Hello s4u"); @@ -48,7 +60,8 @@ namespace s4u { * }; * * // From your main or from another actor, create your actor on the host Jupiter - * new Actor("worker", simgrid::s4u::Host::by_name("Jupiter"), worker); + * // The following line actually creates a new actor, even if there is no "new". + * Actor("Alice", simgrid::s4u::Host::by_name("Jupiter"), worker); * @endcode * * But some people prefer to encapsulate their actors in classes and @@ -68,7 +81,7 @@ namespace s4u { * }; * * // From your main or from another actor, create your actor. Note the () after Worker - * new Actor("worker", simgrid::s4u::Host::by_name("Jupiter"), Worker()); + * Actor("Bob", simgrid::s4u::Host::by_name("Jupiter"), Worker()); * @endcode * * @section s4u_actor_flesh Fleshing your actor @@ -114,18 +127,89 @@ namespace s4u { * * @{ */ - + /** @brief Simulation Agent (see \ref s4u_actor)*/ XBT_PUBLIC_CLASS Actor { - explicit Actor(smx_process_t smx_proc); + friend Mailbox; + friend simgrid::simix::Process; + smx_process_t pimpl_ = nullptr; + + /** Wrap a (possibly non-copyable) single-use task into a `std::function` */ + template + static std::function wrap_task(F f, Args... args) + { + typedef decltype(f(std::move(args)...)) R; + auto task = std::make_shared>( + simgrid::xbt::makeTask(std::move(f), std::move(args)...)); + return [=] { + (*task)(); + }; + } + + Actor(smx_process_t pimpl) : pimpl_(pimpl) {} + public: - Actor(const char* name, s4u::Host *host, double killTime, std::function code); - Actor(const char* name, s4u::Host *host, std::function code) - : Actor(name, host, -1, std::move(code)) {}; - template - Actor(const char* name, s4u::Host *host, C code) - : Actor(name, host, -1, std::function(std::move(code))) {} - ~Actor(); + + // ***** No copy ***** + + Actor(Actor const&) = delete; + Actor& operator=(Actor const&) = delete; + + // ***** Reference count (delegated to pimpl_) ***** + + friend void intrusive_ptr_add_ref(Actor* actor) + { + xbt_assert(actor != nullptr); + SIMIX_process_ref(actor->pimpl_); + } + friend void intrusive_ptr_release(Actor* actor) + { + xbt_assert(actor != nullptr); + SIMIX_process_unref(actor->pimpl_); + } + using Ptr = boost::intrusive_ptr; + + // ***** Actor creation ***** + + /** Create an actor using a function + * + * If the actor is restarted, the actor has a fresh copy of the function. + */ + static Ptr createActor(const char* name, s4u::Host *host, double killTime, std::function code); + + static Ptr createActor(const char* name, s4u::Host *host, std::function code) + { + return createActor(name, host, -1.0, std::move(code)); + } + + /** Create an actor using code + * + * Using this constructor, move-only type can be used. The consequence is + * that we cannot copy the value and restart the process in its initial + * state. In order to use auto-restart, an explicit `function` must be passed + * instead. + */ + template::type + > + static Ptr createActor(const char* name, s4u::Host *host, F code, Args... args) + { + return createActor(name, host, wrap_task(std::move(code), std::move(args)...)); + } + + // Create actor from function name: + + static Ptr createActor(const char* name, s4u::Host *host, double killTime, + const char* function, std::vector args); + + static Ptr createActor(const char* name, s4u::Host *host, const char* function, + std::vector args) + { + return createActor(name, host, -1.0, function, std::move(args)); + } + + // ***** Methods ***** /** Retrieves the actor that have the given PID (or NULL if not existing) */ //static Actor *byPid(int pid); not implemented @@ -152,6 +236,7 @@ public: void kill(); static void kill(int pid); + static Ptr forPid(int pid); /** * Wait for the actor to finish. @@ -162,22 +247,26 @@ public: /** Ask kindly to all actors to die. Only the issuer will survive. */ static void killAll(); - -protected: - smx_process_t getInferior() - { - return pimpl_; - } -private: - smx_process_t pimpl_ = nullptr; + + smx_process_t getInferior(); }; -/** @brief Static methods working on the current actor (see @ref s4u_actor) */ +using ActorPtr = Actor::Ptr; + +/** @ingroup s4u_api + * @brief Static methods working on the current actor (see @ref s4u::Actor) */ namespace this_actor { /** Block the actor sleeping for that amount of seconds (may throws hostFailure) */ XBT_PUBLIC(void) sleep(double duration); + template + inline void sleep(std::chrono::duration duration) + { + auto seconds = std::chrono::duration_cast(duration); + sleep(seconds.count()); + } + /** Block the actor, computing the given amount of flops */ XBT_PUBLIC(e_smx_state_t) execute(double flop); @@ -192,6 +281,11 @@ namespace this_actor { * See \ref Comm for the full communication API (including non blocking communications). */ XBT_PUBLIC(void) send(Mailbox &chan, void*payload, size_t simulatedSize); + + /** + * Return the PID of the current actor. + */ + XBT_PUBLIC(int) getPid(); };