Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid
authorMartin Quinson <martin.quinson@loria.fr>
Fri, 17 Jun 2016 09:39:43 +0000 (11:39 +0200)
committerMartin Quinson <martin.quinson@loria.fr>
Fri, 17 Jun 2016 09:39:43 +0000 (11:39 +0200)
1  2 
include/simgrid/s4u/actor.hpp

@@@ -6,15 -6,25 +6,23 @@@
  #ifndef SIMGRID_S4U_ACTOR_HPP
  #define SIMGRID_S4U_ACTOR_HPP
  
+ #include <atomic>
+ #include <functional>
+ #include <future>
+ #include <memory>
  #include <stdexcept>
+ #include <type_traits>
  #include <xbt/base.h>
+ #include <xbt/functional.hpp>
  #include <simgrid/simix.h>
  #include <simgrid/s4u/forward.hpp>
  
  namespace simgrid {
  namespace s4u {
  
 -/** @addtogroup s4u_actor
 - * 
 - * @tableofcontents
 +/** @ingroup s4u_api
   * 
   * An actor is an independent stream of execution in your distributed application.
   *
@@@ -30,6 -40,8 +38,6 @@@
   * of this standard</a> 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 <a href="http://en.cppreference.com/w/cpp/thread">C++11
@@@ -37,8 -49,6 +45,8 @@@
   * 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");
@@@ -46,8 -56,7 +54,8 @@@
   * };
   * 
   * // From your main or from another actor, create your actor on the host Jupiter
 - * 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
@@@ -67,7 -76,7 +75,7 @@@
   * };
   * 
   * // From your main or from another actor, create your actor. Note the () after Worker
 - * 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
   * 
   *  @{
   */
-    
  /** @brief Simulation Agent (see \ref s4u_actor)*/
  XBT_PUBLIC_CLASS Actor {
+ private:
+   /** Wrap a (possibly non-copyable) single-use task into a `std::function` */
+   template<class F, class... Args>
+   class Task {
+   public:
+     Task(F&& code, Args&&... args) :
+       code_(std::forward<F>(code)),
+       args_(std::forward<Args>(args)...)
+     {}
+     void operator()()
+     {
+       if (done_.test_and_set())
+         throw std::logic_error("Actor task already executed");
+       simgrid::xbt::apply(std::move(code_), std::move(args_));
+     }
+   private:
+     std::atomic_flag done_ = ATOMIC_FLAG_INIT;
+     F code_;
+     std::tuple<Args...> args_;
+   };
+   /** Wrap a (possibly non-copyable) single-use task into a `std::function` */
+   template<class F, class... Args>
+   static std::function<void()> wrap_task(F f, Args... args)
+   {
+     std::shared_ptr<Task<F, Args...>> task(
+       new Task<F, Args...>(std::move(f), std::move(args)...));
+     return [=] {
+       (*task)();
+     };
+   }
  public:
    Actor() : pimpl_(nullptr) {}
    Actor(smx_process_t smx_proc) :
      swap(*this, actor);
    }
  
+   /** Create an actor using a function
+    *
+    *  If the actor is restarted, the actor has a fresh copy of the function.
+    */
    Actor(const char* name, s4u::Host *host, double killTime, std::function<void()> code);
    Actor(const char* name, s4u::Host *host, std::function<void()> code)
-     : Actor(name, host, -1, std::move(code)) {};
-   template<class C>
-   Actor(const char* name, s4u::Host *host, C code)
-     : Actor(name, host, -1, std::function<void()>(std::move(code))) {}
+     : Actor(name, host, -1.0d, 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<class F, class... Args,
+     // This constructor is enabled only if the call code(args...) is valid:
+     typename = typename std::result_of<F(Args...)>::type
+     >
+   Actor(const char* name, s4u::Host *host, F code, Args... args) :
+     Actor(name, host, wrap_task(std::move(code), std::move(args)...))
+   {}
  
    /** Retrieves the actor that have the given PID (or NULL if not existing) */
    //static Actor *byPid(int pid); not implemented
@@@ -189,8 -245,7 +244,8 @@@ private
    smx_process_t pimpl_ = nullptr;
  };
  
 -/** @brief Static methods working on the current actor (see @ref s4u_actor) */
 +/** @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) */