MEL
Microthread & Execution library
utilities.h
Go to the documentation of this file.
1 #pragma once
2 /*
3  * SPDX-FileCopyrightText: 2005,2022 Daniel Barrientos
4  * <danivillamanin@gmail.com>
5  *
6  * SPDX-License-Identifier: MIT
7  */
14 #include <core/Future.h>
15 #include <memory>
16 #include <parallelism/Barrier.h>
17 #include <tasking/Event_mthread.h>
18 #include <utility>
19 namespace mel
20 {
21  namespace tasking
22  {
23 
24  /*
25  template<class T> ::mel::core::WaitResult<T> waitForFutureMThread(
26  const mel::core::Future<T>& f,unsigned int msecs =
27  EVENTMT_WAIT_INFINITE)
28  {
29  using ::mel::tasking::Event_mthread;
30  struct _Receiver
31  {
32  _Receiver():mEvent(false,false){}
33  using futT = mel::core::Future<T>;
34  ::mel::core::EWaitError wait( const futT& f,unsigned int msecs)
35  {
36  EEventMTWaitCode eventResult;
37  int evId;
38  eventResult = mEvent.waitAndDo([this,f,&evId]()
39  {
40  evId = f.subscribeCallback(
41  [this](typename futT::ValueType& )
42  {
43  mEvent.set();
44  }
45  );
46  },msecs);
47  f.unsubscribeCallback(evId); //maybe timeout, so callback
48  won't be unsubscribed automatically switch( eventResult )
49  {
50  case EEventMTWaitCode::EVENTMT_WAIT_OK:
51  return ::mel::core::EWaitError::FUTURE_WAIT_OK;
52  case EEventMTWaitCode::EVENTMT_WAIT_KILL:
53  //event was triggered because a kill signal
54  return
55  ::mel::core::EWaitError::FUTURE_RECEIVED_KILL_SIGNAL; break; case
56  EEventMTWaitCode::EVENTMT_WAIT_TIMEOUT: return
57  ::mel::core::EWaitError::FUTURE_WAIT_TIMEOUT; break; default: return
58  ::mel::core::EWaitError::FUTURE_WAIT_OK; //silent warning
59  }
60  }
61  private:
62  ::mel::tasking::Event_mthread<> mEvent;
63 
64  };
65 
66  auto receiver = std::make_unique<_Receiver>();
67  ::mel::core::EWaitError waitRes = receiver->wait(f,msecs);
68  switch (waitRes)
69  {
70  case ::mel::core::EWaitError::FUTURE_WAIT_OK:
71  if ( f.getValue().isValid())
72  return ::mel::core::WaitResult(f);
73  else
74  std::rethrow_exception(f.getValue().error());
75  break;
76  case ::mel::core::EWaitError::FUTURE_RECEIVED_KILL_SIGNAL:
77  throw
78  mel::core::WaitException(mel::core::EWaitError::FUTURE_RECEIVED_KILL_SIGNAL,"Kill
79  signal received"); break; case
80  ::mel::core::EWaitError::FUTURE_WAIT_TIMEOUT: throw
81  mel::core::WaitException(mel::core::EWaitError::FUTURE_WAIT_TIMEOUT,"Time
82  out exceeded"); break; case
83  ::mel::core::EWaitError::FUTURE_UNKNOWN_ERROR: throw
84  mel::core::WaitException(mel::core::EWaitError::FUTURE_UNKNOWN_ERROR,"Unknown
85  error"); break; default: throw
86  mel::core::WaitException(mel::core::EWaitError::FUTURE_UNKNOWN_ERROR,"Unknown
87  error"); break;
88  }
89  }
90  */
101  template <class ErrorType = mel::core::WaitErrorAsException, class T>
103  const mel::core::Future<T>& f,
104  unsigned int msecs =
105  EVENTMT_WAIT_INFINITE ) noexcept( std::
106  is_same<
107  ErrorType,
108  ::mel::core::
109  WaitErrorNoException>::
110  value )
111  {
112  constexpr bool NotuseException =
113  std::is_same<ErrorType,
115  constexpr bool UseException =
116  std::is_same<ErrorType,
118  static_assert( NotuseException || UseException,
119  "WaitForFutureMThread must specify either "
120  "WaitErrorNoException or WaitErrorAsException" );
121  using ::mel::tasking::Event_mthread;
122  struct _Receiver
123  {
124  _Receiver() : mEvent( false, false ) {}
125  using futT = mel::core::Future<T>;
126  ::mel::core::EWaitError wait( const futT& f,
127  unsigned int msecs )
128  {
129  EEventMTWaitCode eventResult;
130  int evId;
131  eventResult = mEvent.waitAndDo(
132  [this, f, &evId]()
133  {
134  evId = f.subscribeCallback(
135  [this]( typename futT::ValueType& )
136  { this->mEvent.set(); } );
137  },
138  msecs );
140  evId ); // maybe timeout, so callback won't be
141  // unsubscribed automatically
142  switch ( eventResult )
143  {
144  case EEventMTWaitCode::EVENTMT_WAIT_OK:
145  return ::mel::core::EWaitError::FUTURE_WAIT_OK;
146  case EEventMTWaitCode::EVENTMT_WAIT_KILL:
147  // event was triggered because a kill signal
148  return ::mel::core::EWaitError::
149  FUTURE_RECEIVED_KILL_SIGNAL;
150  break;
151  case EEventMTWaitCode::EVENTMT_WAIT_TIMEOUT:
152  return ::mel::core::EWaitError::FUTURE_WAIT_TIMEOUT;
153  break;
154  default:
155  return ::mel::core::EWaitError::
156  FUTURE_WAIT_OK; // silent warning
157  }
158  }
159 
160  private:
162  };
163 
164  ::mel::core::WaitResult result( f );
165  auto receiver = std::make_unique<_Receiver>();
166  ::mel::core::EWaitError waitRes = receiver->wait( f, msecs );
167  if constexpr ( NotuseException )
168  {
169  switch ( waitRes )
170  {
171  case ::mel::core::EWaitError::FUTURE_WAIT_OK:
172  break;
173  case ::mel::core::EWaitError::FUTURE_RECEIVED_KILL_SIGNAL:
174  result.setError(
175  std::make_exception_ptr( mel::core::WaitException(
177  "Kill signal received" ) ) );
178  break;
179  case ::mel::core::EWaitError::FUTURE_WAIT_TIMEOUT:
180  result.setError(
181  std::make_exception_ptr( mel::core::WaitException(
183  "Time out exceeded" ) ) );
184  break;
185  case ::mel::core::EWaitError::FUTURE_UNKNOWN_ERROR:
186  result.setError(
187  std::make_exception_ptr( mel::core::WaitException(
189  "Unknown error" ) ) );
190  break;
191  default:
192  result.setError(
193  std::make_exception_ptr( mel::core::WaitException(
195  "Unknown error" ) ) );
196  break;
197  }
198  }
199  else // verion throwing exception (UseExceptoion == true)
200  {
201  switch ( waitRes )
202  {
203  case ::mel::core::EWaitError::FUTURE_WAIT_OK:
204  if ( f.getValue().isValid() )
205  return ::mel::core::WaitResult( f );
206  else
207  std::rethrow_exception( f.getValue().error() );
208  break;
209  case ::mel::core::EWaitError::FUTURE_RECEIVED_KILL_SIGNAL:
212  "Kill signal received" );
213  break;
214  case ::mel::core::EWaitError::FUTURE_WAIT_TIMEOUT:
217  "Time out exceeded" );
218  break;
219  case ::mel::core::EWaitError::FUTURE_UNKNOWN_ERROR:
222  "Unknown error" );
223  break;
224  default:
227  "Unknown error" );
228  break;
229  }
230  }
231  return result;
232  }
233 
239  MEL_API ::mel::tasking::EEventMTWaitCode waitForBarrierMThread(
240  const ::mel::parallelism::Barrier& b,
241  unsigned int msecs = ::mel::tasking::EVENTMT_WAIT_INFINITE );
242 
243  } // namespace tasking
244 } // namespace mel
int unsubscribeCallback(int id) const
Unsubscribe given callback.
Definition: Future.h:695
Represents a value that maybe is not present at the current moment.
Definition: Future.h:750
Exception class generated by WaitResult when wait for future gets an error.
Definition: Future.h:882
Wrapper for future value after wait.
Definition: Future.h:902
class similar to Event Class (which is for thread synchronization) but for Process (with Microthread ...
Definition: Event_mthread.h:167
base functionalities
Definition: Callback_Impl.h:13
EWaitError
Generic result error codes for future waiting.
Definition: Future.h:29
@ FUTURE_WAIT_TIMEOUT
Time out expired while waiting for Future.
@ FUTURE_UNKNOWN_ERROR
Unknow error while waiting for Future.
MEL_API ::mel::tasking::EEventMTWaitCode waitForBarrierMThread(const ::mel::parallelism::Barrier &b, unsigned int msecs=::mel::tasking::EVENTMT_WAIT_INFINITE)
Wait for a barrier to activated in the context of a microthread.
::mel::core::WaitResult< T > waitForFutureMThread(const mel::core::Future< T > &f, unsigned int msecs=EVENTMT_WAIT_INFINITE) noexcept(std::is_same< ErrorType, ::mel::core::WaitErrorNoException >::value)
Waits for future completion, returning a wapper around the internal vale.
Definition: utilities.h:102
Definition: Callback_Impl.h:11
Policy for treating error as exception in future wait functions.
Definition: Future.h:936
Policy for not treating error as exception in future wait functions.
Definition: Future.h:941