NCBI C++ ToolKit
job_future.hpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 #ifndef GUI_OBJUTILS___JOB_FUTURE__HPP
2 #define GUI_OBJUTILS___JOB_FUTURE__HPP
3 
4 /* $Id: job_future.hpp 47290 2022-12-20 20:37:03Z evgeniev $
5  * ===========================================================================
6  *
7  * PUBLIC DOMAIN NOTICE
8  * National Center for Biotechnology Information
9  *
10  * This software/database is a "United States Government Work" under the
11  * terms of the United States Copyright Act. It was written as part of
12  * the author's official duties as a United States Government employee and
13  * thus cannot be copyrighted. This software/database is freely available
14  * to the public for use. The National Library of Medicine and the U.S.
15  * Government have not placed any restriction on its use or reproduction.
16  *
17  * Although all reasonable efforts have been taken to ensure the accuracy
18  * and reliability of the software and data, the NLM and the U.S.
19  * Government do not and cannot warrant the performance or results that
20  * may be obtained by using this software or data. The NLM and the U.S.
21  * Government disclaim all warranties, express or implied, including
22  * warranties of performance, merchantability or fitness for any particular
23  * purpose.
24  *
25  * Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Authors: Roman Katargin
30  *
31  * File Description:
32  *
33  */
34 
35 ///
36 /// Here is set of classes to implement launching jobs
37 /// (to execute code on a worker thread using C++ Toolkit thread pool implementation)
38 /// This code mimics (not exactly) STL async/future concept (delayed function call).
39 /// There ar two entities - template class job_future<T>, T is returned type.
40 /// and job_async template function which creates job_future<> instance.
41 /// job_async accepts as a parameter a function object created by std::bind() template function or
42 /// lambda function with parameters [](ICanceled& canceled).
43 /// The returned object must have a call signature T f() or T f(ICanceled&).
44 /// Then the returned job_future<> may be polled periodically for completion.
45 /// Recommended way is to use either wxTimer "void OnTimer(wxTimerEvent& event)"
46 /// or OnIdle "void OnIdle(wxIdleEvent& event)".
47 /// After completetion job_future<> object must be "called" via call operator.
48 /// The call will either return a value (may be void) or rethrow an uncaught exception.
49 /// Only std::exception derived exception will be rethrown.
50 /// An Example:
51 ///
52 /// class CSomeGUIClass
53 /// {
54 /// void LaunchJob();
55 /// void OnIdle(wxIdleEvent& event)
56 /// private:
57 /// job_future<vector<string> > m_Future;
58 /// };
59 ///
60 /// void CSomeGUIClass::LaunchJob()
61 /// {
62 /// TConstScopedObjects objects;
63 /// m_Future = job_async([objects](ICanceled& canceled)
64 /// {
65 /// vector<string> result;
66 /// if (canceled.IsCanceled())
67 /// return result;
68 /// ... // implementation
69 /// return result;
70 /// }
71 /// }
72 ///
73 /// void CSomeGUIClass::OnIdle(wxIdleEvent& event)
74 /// {
75 /// if (m_Future.IsComplete()) {
76 /// try {
77 /// vector<string>& res = m_Future();
78 /// ... // do someting with res;
79 /// } catch (const std::exception& e) {
80 /// ... // report error
81 /// }
82 /// m_Future.reset(); // not neccessary but recommended to release resources
83 /// }
84 /// else
85 /// event.Skip();
86 /// }
87 ///
88 /// There is a member job_future<>::cancel() which causes ICanceled::IsCanceled() to return true to interrupt a job.
89 /// On job completion a programmer can check if job_future<>::cancel() was called by "bool job_future<>::IsCanceled()"
90 ///
91 
92 
93 #include <gui/gui_export.h>
94 #include <corelib/ncbiobj.hpp>
95 
99 
101 
103 {
105 public:
107  {
108  public:
109  virtual ~IJobCallback() {}
110  virtual void OnJobResult(CObject* result) = 0;
111  virtual void OnJobFailed(const IAppJobError* error) = 0;
112  virtual void OnJobCanceled() = 0;
113  };
114 
115  CJobFutureAdapter(IJobCallback& callback);
116  ~CJobFutureAdapter() { Detach(); }
117 
118  void Start(IAppJob& job);
119 
120  void Cancel();
121  void Detach();
122 
123  void SetCallback(IJobCallback* callback) { m_Callback = callback; }
124 
125  bool IsRunning() const;
126 
127 private:
128  void x_OnJobNotification(CEvent* evt);
129  void x_CancelJob();
130 
133 };
134 
136  public CObject,
137  public IAppJobError
138 {
139 public:
140  CJobFutureError(const std::exception_ptr& ex) : m_Exception(ex) {}
141 
142  void Rethrow() const
143  {
144  std::rethrow_exception(m_Exception);
145  }
146 
147  /// @name IAppJobError implementation
148  /// @{
149  virtual string GetText() const { return ""; };
150  virtual bool IsUserLevel() const { return false; }
151  /// @}
152 private:
153  std::exception_ptr m_Exception;
154 };
155 
157 {
158 public:
159  job_future_base() : m_State(eUndefined) {}
160  job_future_base(IAppJob& job);
161 
164 
166  {
167  m_State = rhs.m_State;
168  m_Canceled = rhs.m_Canceled;
169  m_Result = std::move(rhs.m_Result);
170  m_Error = std::move(rhs.m_Error);
171  m_JobAdapter = std::move(rhs.m_JobAdapter);
172 
173  if (m_JobAdapter)
174  m_JobAdapter->SetCallback(this);
175 
176  rhs.m_State = eUndefined;
177  rhs.m_Canceled = false;
178  }
179 
181  {
182  if (this == &rhs)
183  return *this;
184 
185  reset();
186 
187  m_State = rhs.m_State;
188  m_Canceled = rhs.m_Canceled;
189  m_Result = std::move(rhs.m_Result);
190  m_Error = std::move(rhs.m_Error);
191  m_JobAdapter = std::move(rhs.m_JobAdapter);
192 
193  if (m_JobAdapter)
194  m_JobAdapter->SetCallback(this);
195 
196  rhs.m_State = eUndefined;
197  rhs.m_Canceled = false;
198 
199  return *this;
200  }
201 
202  virtual ~job_future_base() { reset(); }
203 
204  bool IsRunning() const { return m_JobAdapter ? m_JobAdapter->IsRunning() : false; }
205  bool IsComplete() const { return m_State == eComplete; }
206  bool IsCanceled() const { return m_Canceled; }
207 
208  void reset();
209 
210  void cancel()
211  {
212  if (m_JobAdapter)
213  m_JobAdapter->Cancel();
214  }
215 
216  /// @name CJobFutureAdapter::IJobCallback interface implementation
217  /// @{
218  virtual void OnJobResult(CObject* result);
219  virtual void OnJobFailed(const IAppJobError* error);
220  virtual void OnJobCanceled();
221  /// @}
222 
223 protected:
224  void handle_error();
225 
226  enum EState
227  {
230  eUndefined
231  };
232 
234  bool m_Canceled = false;
238 
239  static const char* m_BadJobResponse;
240 };
241 
242 template<class _Rty>
244 {
245 public:
248 
249  job_future(job_future&& rhs) : job_future_base(std::move(rhs)) {}
250 
252  {
253  job_future_base::operator=(std::move(rhs));
254  return *this;
255  }
256 
257  _Rty& operator()();
258 };
259 
260 class CJobFutureResult : public CObject
261 {
262 public:
264 
265  void SetCanceled() { m_Canceled = true; }
266  bool GetCanceled() const { return m_Canceled; }
267 
268 private:
270 };
271 
272 template<typename T> class CJobFutureResultRet : public CJobFutureResult
273 {
274 public:
275  T& SetData() { return m_Data; }
276 
277 private:
279 };
280 
281 template<class _Rty>
283 {
284  handle_error();
286  = dynamic_cast<CJobFutureResultRet<_Rty>* >(m_Result.GetPointerOrNull());
287  if (result) {
288  m_Canceled = result->GetCanceled();
289  return result->SetData();
290  }
291  throw std::runtime_error(m_BadJobResponse);
292 }
293 
294 template<>
295 class job_future<void> : public job_future_base
296 {
297 public:
300 
301  job_future(job_future&& rhs) : job_future_base(std::move(rhs)) {}
302 
304  {
305  job_future_base::operator=(std::move(rhs));
306  return *this;
307  }
308 
310 };
311 
313 {
314 public:
315  CJobFutureJobBase(const string& descr) : m_Descr() {}
316 
317  /// @name IAppJob implementation
318  /// @{
319  virtual string GetDescr() const { return m_Descr; }
321  {
323  }
325  {
326  return m_Result;
327  }
329  {
331  }
332  /// @}
333 
334 protected:
335  virtual string x_GetJobName() const { return m_Descr; }
336 
337  string m_Descr;
340 };
341 
342 template<class _Fty, typename _Rty> class CJobFutureJob : public CJobFutureJobBase
343 {
344 public:
346 
347  CJobFutureJob(const _Fty& _Fnarg, const string& descr)
348  : CJobFutureJobBase(descr), m_Farg(_Fnarg) {}
349 
350  /// @name IAppJob implementation
351  /// @{
352  virtual EJobState Run();
353  /// @}
354 
355 private:
356  _Fty m_Farg;
357 };
358 
359 template<class _Fty, typename _Rty>
361 {
362  m_Result.Reset(new TResult());
363  TResult& result = static_cast<TResult&>(*m_Result);
364 
365  try {
366  result.SetData() = m_Farg(*x_GetICanceled());
367  }
368  catch (const std::exception&) {
369  m_Error.Reset(new CJobFutureError(std::current_exception()));
370  }
371 
372  if (m_Error)
373  return eFailed;
374 
375  if (IsCanceled())
376  result.SetCanceled();
377 
378  return eCompleted;
379 }
380 
381 template<class _Fty>
382 class CJobFutureJob<_Fty, void> : public CJobFutureJobBase
383 {
384 public:
385  CJobFutureJob(const _Fty& _Fnarg, const string& descr)
386  : CJobFutureJobBase(descr), m_Farg(_Fnarg) {}
387 
388  /// @name IAppJob implementation
389  /// @{
390  virtual EJobState Run();
391  /// @}
392 
393 private:
394  _Fty m_Farg;
395 };
396 
397 template<class _Fty>
399 {
401  CJobFutureResult& result = static_cast<CJobFutureResult&>(*m_Result);
402 
403  try {
405  }
406  catch (const std::exception&) {
407  m_Error.Reset(new CJobFutureError(std::current_exception()));
408  }
409 
410  if (m_Error)
411  return eFailed;
412 
413  if (IsCanceled())
414  result.SetCanceled();
415 
416  return eCompleted;
417 }
418 
419 template<class _Fty>
421 {
425 };
426 
427 template<class _Fty>
428 typename job_function_traits<_Fty>::future job_async(const _Fty& _Fnarg, const string& descr)
429 {
430  typedef job_function_traits<_Fty> tr;
431  CIRef<IAppJob> job(new typename tr::job(_Fnarg, descr));
432  return typename tr::future(*job);
433 }
434 
436 {
437  friend class CJobHandler;
438 
439 public:
440  virtual ~async_job();
441 
442  virtual bool running() = 0;
443  virtual void cancel() = 0;
444 
445 private:
446  virtual bool complete() = 0;
447  virtual bool canceled() = 0;
448 };
449 
451 {
452  friend class async_job;
453 public:
454  static CJobHandler& Instance();
455 
456  void AddJob(async_job* job) { m_Jobs.push_back(job); }
457  bool Process();
458 
459 private:
460  void x_RemoveJob(async_job* job) { m_Jobs.remove(job); }
462 
463  list<async_job*> m_Jobs;
464 };
465 
466 template<class _Fty, typename _Rty>
467 class async_job_impl : public async_job
468 {
469 public:
470  async_job_impl(const _Fty& _Fnres, job_future<_Rty>&& _future) :
471  fnres(_Fnres), future(std::move(_future)) {}
472 
473  virtual bool running() { return future.IsRunning(); }
474  virtual void cancel() { future.cancel(); }
475 
476 private:
477  virtual bool complete() {
478  if (future.IsComplete()) {
479  fnres(future);
480  future.reset();
481  return true;
482  }
483  return false;
484  }
485 
486  virtual bool canceled() { return future.IsCanceled(); }
487 
488  _Fty fnres;
490 };
491 
492 template<class _Fty, class _Fty2>
493 async_job* job_async(const _Fty& _Fnarg, const _Fty2& _Fnarg2, const string& descr)
494 {
495  typedef job_function_traits<_Fty> tr;
496  typedef async_job_impl<_Fty2, typename tr::result> async_job_type;
497  async_job_type* job = new async_job_type(_Fnarg2, job_async(_Fnarg, descr));
499  return job;
500 }
501 
503 
504 /* @} */
505 
506 #endif // GUI_OBJUTILS___JOB_FUTURE__HPP
CEventHandler.
CEvent - generic event implementation TODO TODO - Attachments.
Definition: event.hpp:86
Base class to build jobs with cancel functionality.
virtual void OnJobResult(CObject *result)=0
virtual void OnJobFailed(const IAppJobError *error)=0
Here is set of classes to implement launching jobs (to execute code on a worker thread using C++ Tool...
Definition: job_future.hpp:103
IJobCallback * m_Callback
Definition: job_future.hpp:131
CAppJobDispatcher::TJobID m_JobId
Definition: job_future.hpp:132
void SetCallback(IJobCallback *callback)
Definition: job_future.hpp:123
std::exception_ptr m_Exception
Definition: job_future.hpp:153
virtual string GetText() const
returns a string describing the error
Definition: job_future.hpp:149
void Rethrow() const
Definition: job_future.hpp:142
virtual bool IsUserLevel() const
Definition: job_future.hpp:150
CJobFutureError(const std::exception_ptr &ex)
Definition: job_future.hpp:140
virtual CConstIRef< IAppJobError > GetError()
Returns IAppJobError object describing internal error that caused the Job to fail.
Definition: job_future.hpp:328
CJobFutureJobBase(const string &descr)
Definition: job_future.hpp:315
virtual CConstIRef< IAppJobProgress > GetProgress()
return progress object, the function shall be synchronized internally.
Definition: job_future.hpp:320
CRef< CObject > m_Result
Definition: job_future.hpp:338
virtual CRef< CObject > GetResult()
Returns the Job Result.
Definition: job_future.hpp:324
CConstRef< CJobFutureError > m_Error
Definition: job_future.hpp:339
virtual string x_GetJobName() const
Definition: job_future.hpp:335
virtual string GetDescr() const
Returns a human readable description of the Job (optional)
Definition: job_future.hpp:319
CJobFutureJob(const _Fty &_Fnarg, const string &descr)
Definition: job_future.hpp:385
CJobFutureResultRet< _Rty > TResult
Definition: job_future.hpp:345
virtual EJobState Run()
Function that does all the useful work, called by the Engine.
Definition: job_future.hpp:360
CJobFutureJob(const _Fty &_Fnarg, const string &descr)
Definition: job_future.hpp:347
bool GetCanceled() const
Definition: job_future.hpp:266
list< async_job * > m_Jobs
Definition: job_future.hpp:463
void AddJob(async_job *job)
Definition: job_future.hpp:456
static CJobHandler & Instance()
Definition: job_future.cpp:198
void x_RemoveJob(async_job *job)
Definition: job_future.hpp:460
CObjectEx –.
Definition: ncbiobj.hpp:2531
CObject –.
Definition: ncbiobj.hpp:180
IAppJobError.
Definition: app_job.hpp:65
IAppJob.
Definition: app_job.hpp:82
async_job_impl(const _Fty &_Fnres, job_future< _Rty > &&_future)
Definition: job_future.hpp:470
virtual bool running()
Definition: job_future.hpp:473
virtual void cancel()
Definition: job_future.hpp:474
virtual bool complete()
Definition: job_future.hpp:477
virtual bool canceled()
Definition: job_future.hpp:486
job_future< _Rty > future
Definition: job_future.hpp:489
virtual void cancel()=0
virtual bool running()=0
virtual bool complete()=0
virtual bool canceled()=0
job_future & operator=(job_future &&rhs)
Definition: job_future.hpp:303
job_future(IAppJob &job)
Definition: job_future.hpp:299
job_future(job_future &&rhs)
Definition: job_future.hpp:301
virtual ~job_future_base()
Definition: job_future.hpp:202
job_future_base & operator=(job_future_base const &)=delete
CRef< CObject > m_Result
Definition: job_future.hpp:236
CRef< CJobFutureAdapter > m_JobAdapter
Definition: job_future.hpp:235
CConstRef< CJobFutureError > m_Error
Definition: job_future.hpp:237
bool IsComplete() const
Definition: job_future.hpp:205
job_future_base(job_future_base const &)=delete
bool IsRunning() const
Definition: job_future.hpp:204
bool IsCanceled() const
Definition: job_future.hpp:206
job_future_base(job_future_base &&rhs)
Definition: job_future.hpp:165
job_future_base & operator=(job_future_base &&rhs)
Definition: job_future.hpp:180
static const char * m_BadJobResponse
job_future_base
Definition: job_future.hpp:239
job_future(IAppJob &job)
Definition: job_future.hpp:247
job_future(job_future &&rhs)
Definition: job_future.hpp:249
job_future & operator=(job_future &&rhs)
Definition: job_future.hpp:251
_Rty & operator()()
Definition: job_future.hpp:282
#define T(s)
Definition: common.h:230
#define false
Definition: bool.h:36
static int type
Definition: getdata.c:31
ICanceled * x_GetICanceled()
virtual bool IsCanceled() const override
EJobState
Job states (describe FSM)
Definition: app_job.hpp:86
@ eCompleted
Definition: app_job.hpp:89
@ eFailed
Definition: app_job.hpp:90
TObjectType * GetPointer(void) const THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:1684
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:1439
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
virtual void Process(SOCK sock)=0
Runs asynchronously (from a separate thread) for each request.
#define NCBI_GUIUTILS_EXPORT
Definition: gui_export.h:518
Defines to provide correct exporting from DLLs in Windows.
job_function_traits< _Fty >::future job_async(const _Fty &_Fnarg, const string &descr)
Definition: job_future.hpp:428
Portable reference counted smart and weak pointers using CWeakRef, CRef, CObject and CObjectEx.
CJobFutureJob< _Fty, result > job
Definition: job_future.hpp:423
job_future< result > future
Definition: job_future.hpp:424
std::invoke_result< _Fty, ICanceled & >::type result
Definition: job_future.hpp:422
else result
Definition: token2.c:20
Modified on Wed Sep 04 15:03:36 2024 by modify_doxy.py rev. 669887