AsyncTask.h
Go to the documentation of this file.
1 /*--------------------------------------------------------------------------------------+
2 |
3 | Supplied under applicable software license agreement.
4 |
5 | Copyright (c) 2018 Bentley Systems, Incorporated. All rights reserved.
6 |
7 +---------------------------------------------------------------------------------------*/
8 #pragma once
9 
10 #include <Bentley/Tasks/Tasks.h>
11 #include <Bentley/bset.h>
12 #include <functional>
13 #include <Bentley/BeThread.h>
14 
15 #if defined (THREADING_DEBUG)
16  #include <MobileDgn/Utils/BeDbgHelp.h>
17 
18  #define ASYNC_TASK_ADD_DEBUG_INFO(task, callerFrame) { task->SetStackInfo(BeDbgHelp::GetStackInfoAt(callerFrame)); }
19 
20 #else
21  #define ASYNC_TASK_ADD_DEBUG_INFO(task, callerFrame)
22 #endif
23 
25 
26 struct ITaskScheduler;
27 
28 template <class T> struct PackagedAsyncTask;
29 
30 /*--------------------------------------------------------------------------------------+
31 * @bsiclass Bentley Systems
32 +---------------+---------------+---------------+---------------+---------------+------*/
34 {
35 friend struct AsyncTask;
36 protected:
37  virtual void _OnAsyncTaskCompleted (std::shared_ptr<struct AsyncTask> task) = 0;
38 };
39 
40 /*--------------------------------------------------------------------------------------+
41 * @bsiclass Bentley Systems
42 +---------------+---------------+---------------+---------------+---------------+------*/
43 struct EXPORT_VTABLE_ATTRIBUTE AsyncTask : public std::enable_shared_from_this<AsyncTask>
44  {
45  public:
46  friend struct TaskScheduler;
47  friend struct AsyncTaskRunner;
48 
49  enum class Priority
50  {
51  Inherited = -1,
52  Low = 1,
53  Normal = 2,
54  High = 3
55  };
56 
57  private:
58  BeMutex m_mutex;
59  BeConditionVariable m_completedCV;
60 
61  bset<std::weak_ptr<OnAsyncTaskCompletedListener>, std::owner_less<std::weak_ptr<OnAsyncTaskCompletedListener>>> m_onCompletedListeners;
62 
63  bool m_executed;
64  BeAtomic<bool> m_completed;
65 
66  bvector <bpair<std::shared_ptr<AsyncTask>, std::shared_ptr<ITaskScheduler>>> m_thenTasks;
67  bset<std::shared_ptr<AsyncTask>> m_subTasks;
68  bset<std::shared_ptr<AsyncTask>> m_parentTasks;
69 
70  Priority m_priority;
71 
72 #if defined (THREADING_DEBUG)
73  BeDbgHelp::StackInfo m_stackInfo;
74 #endif
75 
76  private:
77  void SetPriority (Priority priority);
78 
79  void CheckCompletion (BeMutexHolder& lock);
80  void OnCompleted (BeMutexHolder& lock);
81 
82  void AddSubTaskNoLock (std::shared_ptr<AsyncTask> task);
83  void AddParentTaskNoLock (std::shared_ptr<AsyncTask> task);
84 
85  void ProcessTaskCompletion ();
86  void CleanUpTask (std::shared_ptr<AsyncTask> task, bset<std::shared_ptr<AsyncTask>>& tasksToCleanUp);
87 
88  void NotifyOnCompletedListeners ();
89 
90  protected:
91  BENTLEYDLL_EXPORT virtual void _OnExecute ();
92 
93  BENTLEYDLL_EXPORT void RegisterOnCompletedListener (std::shared_ptr<OnAsyncTaskCompletedListener> listener);
94  BENTLEYDLL_EXPORT void UnregisterOnCompletedListener (std::shared_ptr<OnAsyncTaskCompletedListener> listener);
95 
96  BENTLEYDLL_EXPORT void AddThenTask (std::shared_ptr<AsyncTask> task, std::shared_ptr<ITaskScheduler> scheduler = nullptr);
97  BENTLEYDLL_EXPORT void RemoveSubTask (std::shared_ptr<AsyncTask> task);
98  BENTLEYDLL_EXPORT void AddParentTask (std::shared_ptr<AsyncTask> task);
99  BENTLEYDLL_EXPORT void RemoveParentTask (std::shared_ptr<AsyncTask> task);
100  BENTLEYDLL_EXPORT bset<std::shared_ptr<AsyncTask>> GetParentTasks ();
101 
102  BENTLEYDLL_EXPORT static void PushTaskToDefaultSheduler(std::shared_ptr<AsyncTask> task);
103 
104  public:
106 
107  BENTLEYDLL_EXPORT virtual ~AsyncTask ();
108 
109  BENTLEYDLL_EXPORT void AddSubTask (std::shared_ptr<AsyncTask> task);
110 
113  template<typename C>
114  static std::shared_ptr<PackagedAsyncTask<void>> WhenAll(C tasks)
115  {
116  auto whenAll = std::make_shared<PackagedAsyncTask<void>>([]{});
117  for (auto task : tasks)
118  whenAll->AddSubTask(task);
119 
120  // To avoid race condition when adding task might end just before we add it
121  // iterate trought all tasks and remove completed.
122  for (auto task : tasks)
123  if (task->IsCompleted())
124  whenAll->RemoveSubTask(task);
125 
126  PushTaskToDefaultSheduler(whenAll);
127  return whenAll;
128  }
129 
131  BENTLEYDLL_EXPORT bool IsCompleted () const;
132 
133  BENTLEYDLL_EXPORT Priority GetPriority () const;
134 
139  BENTLEYDLL_EXPORT void Wait ();
140 
142  BENTLEYDLL_EXPORT void WaitFor (int milliseconds);
143 
144  BENTLEYDLL_EXPORT void Execute ();
145 
146 #if defined (THREADING_DEBUG)
147  void SetStackInfo(const BeDbgHelp::StackInfo& stackInfo)
148  {
149  m_stackInfo = stackInfo;
150  }
151 #endif
152  };
153 
154 /*--------------------------------------------------------------------------------------+
155 * @bsiclass Bentley Systems
156 +---------------+---------------+---------------+---------------+---------------+------*/
157 template <class T, class P> struct PackagedThenAsyncTask;
158 
159 template <class T>
161  {
162  private:
163  std::function<T (void)> m_taskCallback;
164 
165  protected:
167 
168  public:
169  PackagedAsyncTask (const std::function<T (void)>& taskCallback) : AsyncTask (), m_taskCallback (taskCallback), m_result ()
170  {
171  }
172 
173  virtual void _OnExecute ()
174  {
175  m_result = m_taskCallback ();
176  }
177 
179  T& GetResult ()
180  {
181  Wait (); return m_result;
182  }
183 
184  template <class R>
186  std::shared_ptr<PackagedThenAsyncTask<R, T>> Then (const std::function<R (T&)>& taskCallback)
187  {
188  auto task = std::make_shared<PackagedThenAsyncTask<R, T>> (taskCallback, std::shared_ptr <T> (shared_from_this (), &m_result));
189  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
190  AddThenTask (task);
191  return task;
192  }
193 
194  template <class R>
196  std::shared_ptr<PackagedThenAsyncTask<R, T>> Then (std::shared_ptr<ITaskScheduler> scheduler, const std::function<R (T&)>& taskCallback)
197  {
198  auto task = std::make_shared<PackagedThenAsyncTask<R, T>> (taskCallback, std::shared_ptr <T> (shared_from_this (), &m_result));
199  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
200  AddThenTask (task, scheduler);
201  return task;
202  }
203 
205  std::shared_ptr<PackagedThenAsyncTask<void, T>> Then (std::shared_ptr<ITaskScheduler> scheduler, const std::function<void (T&)>& taskCallback)
206  {
207  auto task = std::make_shared<PackagedThenAsyncTask<void, T>> (taskCallback, std::shared_ptr <T> (shared_from_this (), &m_result));
208  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
209  AddThenTask (task, scheduler);
210  return task;
211  }
212 
214  std::shared_ptr<PackagedThenAsyncTask<void, T>> Then (const std::function<void (T&)>& taskCallback)
215  {
216  auto task = std::make_shared<PackagedThenAsyncTask<void, T>> (taskCallback, std::shared_ptr <T> (shared_from_this (), &m_result));
217  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
218  AddThenTask (task);
219  return task;
220  }
221  };
222 
223 /*--------------------------------------------------------------------------------------+
224 * @bsiclass Bentley Systems
225 +---------------+---------------+---------------+---------------+---------------+------*/
226 template <>
228  {
229  protected:
230  std::function<void (void)> m_taskCallback;
231 
232  public:
233  PackagedAsyncTask (const std::function<void (void)>& taskCallback) : AsyncTask (), m_taskCallback (taskCallback)
234  {
235  }
236 
237  virtual void _OnExecute ()
238  {
239  m_taskCallback ();
240  }
241 
242  template <class R>
244  std::shared_ptr<PackagedAsyncTask<R>> Then (const std::function<R (void)>& taskCallback)
245  {
246  auto task = std::make_shared<PackagedAsyncTask<R>> (taskCallback);
247  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
248  AddThenTask (task);
249  return task;
250  }
251 
252  template <class R>
254  std::shared_ptr<PackagedAsyncTask<R>> Then (std::shared_ptr<ITaskScheduler> scheduler, const std::function<R (void)>& taskCallback)
255  {
256  auto task = std::make_shared<PackagedAsyncTask<R>> (taskCallback);
257  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
258  AddThenTask (task, scheduler);
259  return task;
260  }
261 
263  std::shared_ptr<PackagedAsyncTask<void>> Then (const std::function<void (void)>& taskCallback)
264  {
265  auto task = std::make_shared<PackagedAsyncTask<void>> (taskCallback);
266  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
267  AddThenTask (task);
268  return task;
269  }
270 
272  std::shared_ptr<PackagedAsyncTask<void>> Then (std::shared_ptr<ITaskScheduler> scheduler, const std::function<void (void)>& taskCallback)
273  {
274  auto task = std::make_shared<PackagedAsyncTask<void>> (taskCallback);
275  ASYNC_TASK_ADD_DEBUG_INFO(task, 2);
276  AddThenTask (task, scheduler);
277  return task;
278  }
279  };
280 
281 template <class T>
282 using AsyncTaskPtr = std::shared_ptr<PackagedAsyncTask<T>>;
283 
284 /*--------------------------------------------------------------------------------------+
285 * @bsiclass Bentley Systems
286 +---------------+---------------+---------------+---------------+---------------+------*/
287 template <class T, class P>
289  {
290  private:
291  std::shared_ptr<P> m_parentResult;
292 
293  std::function<T (P&)> m_taskCallback;
294 
295  public:
296  PackagedThenAsyncTask (const std::function<T (P&)>& taskCallback, std::shared_ptr<P> parentResult)
297  : PackagedAsyncTask<T> (nullptr),
298  m_taskCallback (taskCallback),
299  m_parentResult (parentResult)
300  {
301  }
302 
303  virtual void _OnExecute ()
304  {
305  this->m_result = this->m_taskCallback (*m_parentResult.get ());
306  }
307  };
308 
309 /*--------------------------------------------------------------------------------------+
310 * @bsiclass Bentley Systems
311 +---------------+---------------+---------------+---------------+---------------+------*/
312 template <class P>
314  {
315  private:
316  std::shared_ptr<P> m_parentResult;
317 
318  std::function<void (P&)> m_taskCallback;
319 
320  public:
321  PackagedThenAsyncTask (const std::function<void (P&)>& taskCallback, std::shared_ptr<P> parentResult)
322  : PackagedAsyncTask<void> (nullptr),
323  m_taskCallback (taskCallback),
324  m_parentResult (parentResult)
325  {
326  }
327 
328  virtual void _OnExecute ()
329  {
330  this->m_taskCallback (*m_parentResult.get ());
331  }
332  };
333 
334 /*--------------------------------------------------------------------------------------+
335 * @bsiclass Bentley Systems
336 +---------------+---------------+---------------+---------------+---------------+------*/
337 template <typename T>
340  {
341  auto task = std::make_shared<PackagedAsyncTask<T>> ([=]
342  {
343  return result;
344  });
345  task->Execute ();
346  return task;
347  }
348 
349 /*--------------------------------------------------------------------------------------+
350 * @bsiclass Bentley Systems
351 +---------------+---------------+---------------+---------------+---------------+------*/
353 BENTLEYDLL_EXPORT AsyncTaskPtr<void> CreateCompletedAsyncTask ();
354 
#define BENTLEYDLL_EXPORT
Definition: Bentley.h:249
A synchronization primitive that can be used to block a thread, or multiple threads at the same time...
Definition: BeThread.h:132
Definition: AsyncTask.h:28
PackagedAsyncTask(const std::function< T(void)> &taskCallback)
Definition: AsyncTask.h:169
Definition: AsyncTask.h:43
The default file attribute.
Together with the BeCriticalSection.h file provides Bentley specific thread handling functions (Bentl...
#define ASYNC_TASK_ADD_DEBUG_INFO(task, callerFrame)
Definition: AsyncTask.h:21
Provides Bentley specific set implementation (Bentley/bset.h).
A BeMutex ownership wrapper.
Definition: BeThread.h:82
std::shared_ptr< PackagedThenAsyncTask< void, T > > Then(const std::function< void(T &)> &taskCallback)
Execute new task with callback code in default thread after this task is finished.
Definition: AsyncTask.h:214
std::shared_ptr< PackagedAsyncTask< R > > Then(std::shared_ptr< ITaskScheduler > scheduler, const std::function< R(void)> &taskCallback)
Execute new task with callback code in sheduler/thread/pool after this task is finished.
Definition: AsyncTask.h:254
T m_result
Definition: AsyncTask.h:166
virtual void _OnExecute()
Definition: AsyncTask.h:303
std::shared_ptr< PackagedThenAsyncTask< R, T > > Then(std::shared_ptr< ITaskScheduler > scheduler, const std::function< R(T &)> &taskCallback)
Execute new task with callback code in sheduler/thread/pool after this task is finished.
Definition: AsyncTask.h:196
virtual void _OnExecute()
Definition: AsyncTask.h:328
PackagedAsyncTask(const std::function< void(void)> &taskCallback)
Definition: AsyncTask.h:233
std::shared_ptr< PackagedAsyncTask< R > > Then(const std::function< R(void)> &taskCallback)
Execute new task with callback code in default thread after this task is finished.
Definition: AsyncTask.h:244
std::shared_ptr< PackagedAsyncTask< void > > Then(const std::function< void(void)> &taskCallback)
Execute new task with callback code in default thread after this task is finished.
Definition: AsyncTask.h:263
#define BEGIN_BENTLEY_TASKS_NAMESPACE
Definition: Tasks.h:13
AsyncTaskPtr< void > CreateCompletedAsyncTask()
Create task that is flagged as completed without executing it.
std::function< void(void)> m_taskCallback
Definition: AsyncTask.h:230
Definition: AsyncTaskRunner.h:20
Definition: AsyncTask.h:157
Priority
Definition: AsyncTask.h:49
std::shared_ptr< PackagedThenAsyncTask< R, T > > Then(const std::function< R(T &)> &taskCallback)
Execute new task with callback code in default thread after this task is finished.
Definition: AsyncTask.h:186
virtual void _OnExecute()
Definition: AsyncTask.h:173
A synchronization primitive that can be used to protect shared data from being simultaneously accesse...
Definition: BeThread.h:57
std::shared_ptr< PackagedThenAsyncTask< void, T > > Then(std::shared_ptr< ITaskScheduler > scheduler, const std::function< void(T &)> &taskCallback)
Execute new task with callback code in sheduler/thread/pool after this task is finished.
Definition: AsyncTask.h:205
virtual void _OnExecute()
Definition: AsyncTask.h:237
PackagedThenAsyncTask(const std::function< T(P &)> &taskCallback, std::shared_ptr< P > parentResult)
Definition: AsyncTask.h:296
std::shared_ptr< PackagedAsyncTask< T >> AsyncTaskPtr
Definition: AsyncTask.h:282
#define END_BENTLEY_TASKS_NAMESPACE
Definition: Tasks.h:14
T & GetResult()
Blocks until result is available. See Wait()
Definition: AsyncTask.h:179
Definition: TaskScheduler.h:77
std::shared_ptr< PackagedAsyncTask< void > > Then(std::shared_ptr< ITaskScheduler > scheduler, const std::function< void(void)> &taskCallback)
Execute new task with callback code in sheduler/thread/pool after this task is finished.
Definition: AsyncTask.h:272
#define EXPORT_VTABLE_ATTRIBUTE
Definition: Bentley.h:67
static std::shared_ptr< PackagedAsyncTask< void > > WhenAll(C tasks)
Create task that will complete once all task in container are completed.
Definition: AsyncTask.h:114
PackagedThenAsyncTask(const std::function< void(P &)> &taskCallback, std::shared_ptr< P > parentResult)
Definition: AsyncTask.h:321

Copyright © 2017 Bentley Systems, Incorporated. All rights reserved.