libqi-api  release-2.5.3-2016-11-18
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
strand.hpp
Go to the documentation of this file.
1 #pragma once
2 /*
3 ** Copyright (C) 2012 Aldebaran Robotics
4 ** See COPYING for the license
5 */
6 
7 #ifndef _QI_STRAND_HPP_
8 #define _QI_STRAND_HPP_
9 
10 #include <deque>
11 #include <atomic>
12 #include <qi/assert.hpp>
14 #include <boost/enable_shared_from_this.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include <boost/function.hpp>
17 #include <boost/noncopyable.hpp>
18 #include <boost/type_traits/function_traits.hpp>
19 
20 # ifdef _MSC_VER
21 # pragma warning( push )
22 # pragma warning( disable: 4996 ) // TODO: Reactivate this warning once msvc stop triggerring a warning on overloading a deprecated function
23 # endif
24 
25 namespace qi
26 {
27 
28 namespace detail
29 {
30 
31  // C++14 this can be a lambda, but we need perfect forwarding in the capture in scheduleFor below
32  template <typename F>
33  struct WrapInStrand;
34 
35 }
36 
37 // we use ExecutionContext's helpers in schedulerFor, we don't need to implement all the methods
38 class StrandPrivate : public ExecutionContext, public boost::enable_shared_from_this<StrandPrivate>
39 {
40 public:
41  enum class State;
42 
43  struct Callback;
44 
45  using Queue = std::deque<boost::shared_ptr<Callback>>;
46 
48  std::atomic<unsigned int> _curId;
49  std::atomic<unsigned int> _aliveCount;
50  bool _processing; // protected by mutex, no need for atomic
51  std::atomic<int> _processingThread;
52  boost::mutex _mutex;
53  boost::condition_variable _processFinished;
54  bool _dying;
56 
58 
59  Future<void> asyncAtImpl(boost::function<void()> cb, qi::SteadyClockTimePoint tp) override;
60  Future<void> asyncDelayImpl(boost::function<void()> cb, qi::Duration delay) override;
61 
62  boost::shared_ptr<Callback> createCallback(boost::function<void()> cb);
63  void enqueue(boost::shared_ptr<Callback> cbStruct);
64 
65  void process();
66  void cancel(boost::shared_ptr<Callback> cbStruct);
67 
68  // don't care
69  bool isInThisContext() override { QI_ASSERT(false); throw 0; }
70  void postImpl(boost::function<void()> callback) override { QI_ASSERT(false); throw 0; }
71  qi::Future<void> async(const boost::function<void()>& callback, qi::SteadyClockTimePoint tp) override
72  { QI_ASSERT(false); throw 0; }
73  qi::Future<void> async(const boost::function<void()>& callback, qi::Duration delay) override
74  { QI_ASSERT(false); throw 0; }
76 private:
77  void stopProcess(boost::mutex::scoped_lock& lock,
78  bool finished);
79 };
80 
82  : _eventLoop(eventLoop)
83  , _curId(0)
84  , _aliveCount(0)
85  , _processing(false)
86  , _processingThread(0)
87  , _dying(false)
88 {
89 }
90 
101 class QI_API Strand : public ExecutionContext, private boost::noncopyable
102 {
103 public:
105  Strand();
107  Strand(qi::ExecutionContext& executionContext);
109  ~Strand();
110 
118  void join();
119 
120  // DEPRECATED
121  QI_API_DEPRECATED_MSG(Use 'asyncAt' instead)
122  qi::Future<void> async(const boost::function<void()>& cb,
123  qi::SteadyClockTimePoint tp) override;
124  QI_API_DEPRECATED_MSG(Use 'asyncDelay' instead)
125  qi::Future<void> async(const boost::function<void()>& cb,
126  qi::Duration delay) override;
128 
129 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
130  template <typename T, typename F, typename ARG0 comma ATYPEDECL> \
131  QI_API_DEPRECATED_MSG(Use generic 'schedulerFor' overload instead) boost::function<T> schedulerFor( \
132  const F& func, const ARG0& arg0 comma ADECL, \
133  const boost::function<void()>& fallbackCb = boost::function<void()>()) \
134  { \
135  boost::function<T> funcbind = qi::bind<T>(func, arg0 comma AUSE); \
136  return qi::trackWithFallback( \
137  fallbackCb, \
138  SchedulerHelper<boost::function_traits<T>::arity, T>::_scheduler( \
139  funcbind, this), \
140  arg0); \
141  }
142  QI_GEN(genCall)
143 #undef genCall
144  // END DEPRECATED
145 
150  bool isInThisContext() override;
151 
152  template <typename F>
153  auto schedulerFor(F&& func, boost::function<void()> onFail = {})
154  -> detail::WrapInStrand<typename std::decay<F>::type>
155  {
156  return detail::WrapInStrand<typename std::decay<F>::type>(std::forward<F>(func),
157  _p,
158  std::move(onFail));
159  }
160 
161 private:
162  boost::shared_ptr<StrandPrivate> _p;
163 
164  void postImpl(boost::function<void()> callback) override;
165 
166  qi::Future<void> asyncAtImpl(boost::function<void()> cb, qi::SteadyClockTimePoint tp) override;
167  qi::Future<void> asyncDelayImpl(boost::function<void()> cb, qi::Duration delay) override;
168 
169  // DEPRECATED
170  template <int N, typename T>
171  struct SchedulerHelper;
172 #define typedefi(z, n, _) \
173  typedef typename boost::function_traits<T>::BOOST_PP_CAT( \
174  BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type) BOOST_PP_CAT(P, n);
175 #define placeholders(z, n, __) , BOOST_PP_CAT(_, BOOST_PP_INC(n))
176 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
177  template <typename T> \
178  struct SchedulerHelper<n, T> \
179  { \
180  BOOST_PP_REPEAT(n, typedefi, _); \
181  typedef typename boost::function_traits<T>::result_type R; \
182  static boost::function<T> _scheduler(const boost::function<T>& f, \
183  Strand* strand) \
184  { \
185  return qi::bind<T>(&_asyncCall, strand, \
186  f BOOST_PP_REPEAT(n, placeholders, _)); \
187  } \
188  static qi::Future<R> _asyncCall(Strand* strand, \
189  const boost::function<T>& func comma \
190  ADECL) \
191  { \
192  /* use qi::bind again since first arg may be a Trackable */ \
193  return ((qi::ExecutionContext*)strand) \
194  ->async(qi::bind<R()>(func comma AUSE)); \
195  } \
196  };
197  QI_GEN(genCall)
198 #undef genCall
199 #undef placeholders
200 #undef typedefi
201  // END DEPRECATED
202 };
203 
204 namespace detail
205 {
206  template <typename F, typename... Args>
207  static auto callInStrand(
208  F& func,
209  const boost::function<void()>& onFail,
210  boost::weak_ptr<StrandPrivate> weakStrand,
211  Args&&... args)
213  {
214  if (auto strand = weakStrand.lock())
215  return strand->async(std::bind(func, std::forward<Args>(args)...));
216  else
217  {
218  if (onFail)
219  onFail();
220  return qi::makeFutureError<
221  typename std::decay<decltype(func(std::forward<Args>(args)...))>::type>("strand is dead");
222  }
223  }
224  // C++14 this can be a lambda, but we need perfect forwarding in the capture in scheduleFor below
225  template <typename F>
226  struct WrapInStrand
227  {
228  static const bool is_async = true;
229 
230  F _func;
231  boost::weak_ptr<StrandPrivate> _strand;
232  boost::function<void()> _onFail;
233 
234  WrapInStrand(F f, boost::weak_ptr<StrandPrivate> strand, boost::function<void()> onFail)
235  : _func(std::move(f))
236  , _strand(std::move(strand))
237  , _onFail(std::move(onFail))
238  {
239  }
240 
241  template <typename... Args>
242  auto operator()(Args&&... args) const
243  -> decltype(callInStrand(_func, _onFail, _strand, std::forward<Args>(args)...))
244  {
245  return callInStrand(_func, _onFail, _strand, std::forward<Args>(args)...);
246  }
247 
248  template <typename... Args>
249  auto operator()(Args&&... args)
250  -> decltype(callInStrand(_func, _onFail, _strand, std::forward<Args>(args)...))
251  {
252  return callInStrand(_func, _onFail, _strand, std::forward<Args>(args)...);
253  }
254  };
255 } // detail
256 } // qi
257 
258 # ifdef _MSC_VER
259 # pragma warning( pop )
260 # endif
261 
262 #endif // _QI_STRAND_HPP_
std::atomic< unsigned int > _aliveCount
Definition: strand.hpp:49
std::atomic< unsigned int > _curId
Definition: strand.hpp:48
boost::shared_ptr< Callback > createCallback(boost::function< void()> cb)
auto schedulerFor(F &&func, boost::function< void()> onFail={}) -> detail::WrapInStrand< typename std::decay< F >::type >
Definition: strand.hpp:153
#define QI_API
Definition: api.hpp:33
qi::Future< void > async(const boost::function< void()> &callback, qi::SteadyClockTimePoint tp) override
Definition: strand.hpp:71
boost::function< void()> _onFail
Definition: strand.hpp:232
SteadyClock::time_point SteadyClockTimePoint
Steady clock time point.
Definition: clock.hpp:211
Future< void > asyncAtImpl(boost::function< void()> cb, qi::SteadyClockTimePoint tp) override
std::deque< boost::shared_ptr< Callback >> Queue
Definition: strand.hpp:45
virtual qi::Future< void > async(const boost::function< void()> &callback, qi::SteadyClockTimePoint tp)=0
auto operator()(Args &&...args) -> decltype(callInStrand(_func, _onFail, _strand, std::forward< Args >(args)...))
Definition: strand.hpp:249
boost::condition_variable _processFinished
Definition: strand.hpp:53
#define QI_ASSERT(expr__)
Definition: assert.hpp:27
boost::weak_ptr< StrandPrivate > _strand
Definition: strand.hpp:231
void cancel(boost::shared_ptr< Callback > cbStruct)
qi::Future< T > makeFutureError(const std::string &error)
Helper function to return a future with the error set.
Definition: future.hxx:601
WrapInStrand(F f, boost::weak_ptr< StrandPrivate > strand, boost::function< void()> onFail)
Definition: strand.hpp:234
#define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)
Definition: strand.hpp:176
bool isInThisContext() override
return true if the current thread is in this context
Definition: strand.hpp:69
NanoSeconds Duration
Definition: clock.hpp:32
qi::ExecutionContext & _eventLoop
Definition: strand.hpp:47
void postImpl(boost::function< void()> callback) override
Definition: strand.hpp:70
static const bool is_async
Definition: strand.hpp:228
auto operator()(Args &&...args) const -> decltype(callInStrand(_func, _onFail, _strand, std::forward< Args >(args)...))
Definition: strand.hpp:242
Future< R > async(boost::function< R()> callback, uint64_t usDelay)
Definition: eventloop.hpp:186
StrandPrivate(qi::ExecutionContext &eventLoop)
Definition: strand.hpp:81
#define QI_API_DEPRECATED_MSG(msg__)
Compiler flags to mark a function as deprecated. It will generate a compiler warning.
Definition: macro.hpp:53
qi::Future< void > async(const boost::function< void()> &callback, qi::Duration delay) override
Definition: strand.hpp:73
std::atomic< int > _processingThread
Definition: strand.hpp:51
Future< void > asyncDelayImpl(boost::function< void()> cb, qi::Duration delay) override
boost::mutex _mutex
Definition: strand.hpp:52
void enqueue(boost::shared_ptr< Callback > cbStruct)
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:327
#define QI_GEN(f)
Definition: preproc.hpp:476