EasyLocalpp  3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
interruptible.hh
Go to the documentation of this file.
1 #if !defined(_INTERRUPTIBLE_HH_)
2 #define _INTERRUPTIBLE_HH_
3 
4 #include <iostream>
5 #include <future>
6 #include <chrono>
7 #include <atomic>
8 #include <thread>
9 #include <condition_variable>
10 
11 
12 namespace EasyLocal {
13 
14  namespace Core {
15 
16  /* Hack for simulating sleep_for when the compiler is not defininig it (e.g., macports g++ >= 4.6). */
17 #if HAVE_THIS_THREAD_SLEEP_FOR
18  template <class Rep, class Period>
19  void sleep_for(std::chrono::duration<Rep, Period> sleep_duration)
20  {
21  std::this_thread::sleep_for(sleep_duration);
22  }
23 #else
24  template <class Rep, class Period>
25  void sleep_for(std::chrono::duration<Rep, Period> sleep_duration)
26  {
27  std::condition_variable c;
28  std::mutex m;
29  std::unique_lock<std::mutex> l(m);
30  c.wait_for(l, sleep_duration);
31  }
32 #endif
33 
34 
36  template <typename Rtype, typename ... Args>
38  {
39  public:
40 
42  Interruptible() : timeout_expired(false) {}
43 
48  Rtype SyncRun(std::chrono::milliseconds timeout, Args... args)
49  {
50  timeout_expired = false;
51  std::future<Rtype> result = std::async(std::launch::async, this->MakeFunction(), std::ref(args) ...);
52 
53  // If timeout is greater than zero
54  if (timeout.count() != 0)
55  {
56  result.wait_for(timeout);
57  if (result.wait_for(std::chrono::milliseconds::zero()) != std::future_status::ready)
58  {
59  timeout_expired = true;
61  }
62  }
63  else
64  {
65  result.wait();
66  }
67  return result.get();
68  }
69 
74  std::shared_future<Rtype> AsyncRun(std::chrono::milliseconds timeout, Args... args)
75  {
76  timeout_expired = false;
77  std::shared_future<Rtype> result = std::async(std::launch::async, this->MakeFunction(), std::ref(args) ...);
78 
79  // If timeout is greater than zero, launch stopper thread
80  if (timeout.count() != 0)
81  {
82  std::thread t([this, timeout, result]()
83  {
84  sleep_for(timeout);
85  // If the function has not returned a value already
86  if (result.wait_for(std::chrono::milliseconds::zero()) == std::future_status::ready) {
87  timeout_expired = true;
89  }
90 
91  });
92  t.detach();
93  }
94  return result;
95  }
96 
98  inline void Interrupt() {
99  timeout_expired = true;
100  }
101 
102  protected:
103 
105  inline const std::atomic<bool>& TimeoutExpired() { return timeout_expired; }
106 
108  inline virtual std::function<Rtype(Args& ...)> MakeFunction() {
109  // Default behavior
110  return [](Args& ...) -> Rtype {
111  return Rtype();
112  };
113  }
114 
116  inline virtual void AtTimeoutExpired() {}
117 
118  private:
119 
121  std::atomic<bool> timeout_expired;
122  };
123  }
124 }
125 
126 #endif
Rtype SyncRun(std::chrono::milliseconds timeout, Args...args)
virtual std::function< Rtype(Args &...)> MakeFunction()
std::shared_future< Rtype > AsyncRun(std::chrono::milliseconds timeout, Args...args)
void sleep_for(std::chrono::duration< Rep, Period > sleep_duration)
const std::atomic< bool > & TimeoutExpired()