SSCMA-Micro CPP SDK  v2.0.0
SSCMA-Micro is a cross-platform machine learning inference framework designed for embedded devices.
ma_executor.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <atomic>
4 #include <functional>
5 #include <memory>
6 #include <queue>
7 #include <string>
8 #include <utility>
9 
10 #include "../ma_common.h"
11 #include "porting/ma_osal.h"
12 
13 namespace ma {
14 
15 typedef std::function<void(std::atomic<bool>&)> task_t;
16 
17 class Executor {
18  public:
19  Executor(std::size_t stack_size = MA_SEVER_AT_EXECUTOR_STACK_SIZE, std::size_t priority = MA_SEVER_AT_EXECUTOR_TASK_PRIO)
20  : _task_queue_lock(), _task_reload(false), _worker_name(MA_EXECUTOR_WORKER_NAME_PREFIX), _worker_handler() {
21  static uint8_t worker_id = 0u;
22  static const char* hex_literals = "0123456789ABCDEF";
23 
24  worker_id++;
25 
26  // prepare worker name (FreeRTOS task required), reserve 2 bytes for uint8_t hex string
27  _worker_name.reserve(_worker_name.length() + (sizeof(uint8_t) << 1) + 1);
28 
29  // convert worker id to hex string
30  _worker_name += hex_literals[worker_id >> 4];
31  _worker_name += hex_literals[worker_id & 0x0f];
32 
33  _worker_handler = new Thread(_worker_name.c_str(), &Executor::c_run, this, priority, stack_size);
34  MA_ASSERT(_worker_handler);
35  if (!_worker_handler->start(this)) {
36  delete _worker_handler;
37  MA_ASSERT(false);
38  }
39  }
40 
42  cancel();
43  _worker_handler->stop();
44  delete _worker_handler;
45  }
46 
47  // the Callable must be a function object or a lambda, the prototype is task_t
48  template <typename Callable> inline void submit(Callable&& callable) {
49  const Guard guard(_task_queue_lock);
50  _task_queue.push(std::forward<Callable>(callable));
51  MA_LOGD("E", "Executor::submit: %s, task count = %zu", _worker_name.c_str(), _task_queue.size());
52  }
53 
54  inline void cancel() {
55  const Guard guard(_task_queue_lock);
56  while (!_task_queue.empty()) _task_queue.pop();
57  }
58 
59  protected:
60  void run() {
61  while (true) {
63  Thread::yield();
64  task_t task{};
65  const Guard guard(_task_queue_lock);
66  if (!_task_queue.empty()) [[likely]] {
67  task = std::move(_task_queue.front()); // or std::function::swap
68  _task_queue.pop();
69  }
70  if (task) [[likely]] {
71  _task_reload.store(false);
72  task(_task_reload);
73  if (_task_reload.load()) [[unlikely]]
74  _task_queue.push(std::move(task)); // put back the task
75  }
76  }
77  }
78 
79  static void c_run(void* this_pointer) { static_cast<Executor*>(this_pointer)->run(); }
80 
81  private:
82  Mutex _task_queue_lock;
83  std::atomic<bool> _task_reload;
84  std::string _worker_name;
85  Thread* _worker_handler;
86 
87  std::queue<task_t> _task_queue;
88 };
89 
90 } // namespace ma
Definition: ma_executor.hpp:17
~Executor()
Definition: ma_executor.hpp:41
Executor(std::size_t stack_size=MA_SEVER_AT_EXECUTOR_STACK_SIZE, std::size_t priority=MA_SEVER_AT_EXECUTOR_TASK_PRIO)
Definition: ma_executor.hpp:19
static void c_run(void *this_pointer)
Definition: ma_executor.hpp:79
void run()
Definition: ma_executor.hpp:60
void submit(Callable &&callable)
Definition: ma_executor.hpp:48
void cancel()
Definition: ma_executor.hpp:54
Definition: ma_osal.h:98
Definition: ma_osal.h:80
Definition: ma_osal.h:40
bool stop()
static void yield()
bool start(void *arg=nullptr)
static void sleep(ma_tick_t tick)
static ma_tick_t fromMilliseconds(uint32_t ms)
#define MA_LOGD(TAG,...)
Definition: ma_debug.h:79
#define MA_ASSERT(expr)
Definition: ma_debug.h:119
#define MA_EXECUTOR_WORKER_NAME_PREFIX
Definition: ma_definations.h:11
#define MA_SEVER_AT_EXECUTOR_TASK_PRIO
Definition: ma_server_at.h:17
#define MA_SEVER_AT_EXECUTOR_STACK_SIZE
Definition: ma_server_at.h:13
Definition: ma_cv.cpp:7
std::function< void(std::atomic< bool > &)> task_t
Definition: ma_executor.hpp:15