From dc04cd8dcee281b41acfe78dea9d49e290247b20 Mon Sep 17 00:00:00 2001 From: Erki Date: Sun, 24 Oct 2021 22:48:57 +0300 Subject: [PATCH] WIP commit --- Threads/Inc/threads_actor.hpp | 134 +++++++++++++++------------ Threads/Inc/threads_actor_thread.hpp | 43 +++++++++ Threads/Src/threads_actor_thread.cpp | 69 ++++++++++++++ 3 files changed, 187 insertions(+), 59 deletions(-) create mode 100644 Threads/Inc/threads_actor_thread.hpp create mode 100644 Threads/Src/threads_actor_thread.cpp diff --git a/Threads/Inc/threads_actor.hpp b/Threads/Inc/threads_actor.hpp index 607615a..1bee6c9 100644 --- a/Threads/Inc/threads_actor.hpp +++ b/Threads/Inc/threads_actor.hpp @@ -18,12 +18,46 @@ #include "threads_primitivethread.hpp" #include "threads_signal.hpp" #include "threads_timer.hpp" +#include "threads_actor_thread.hpp" namespace Threads { +class IActor +{ +public: + IActor() = delete; + IActor(ActorThread* thread) + { + moveToThread(thread); + } + + virtual ~IActor() + { } + + virtual void init() + { } + + virtual void doWork() = 0; + virtual bool hasWork() = 0; + + void moveToThread(ActorThread* thread) + { + assert(thread); + + if (thread_) + thread_->removeActor_(this); + + thread->acceptActor_(this); + thread_ = thread; + } + +protected: + ActorThread* thread_ = nullptr; +}; + template -class Actor +class Actor : public IActor { public: using value_type = std::variant; @@ -31,8 +65,8 @@ public: static_assert(std::is_default_constructible_v, "Ts must be default constructible."); static_assert(std::is_trivially_copyable_v, "Ts must be trivially copyable."); - Actor(const std::uint32_t queue_size, const char* name, const osPriority_t priority, const std::uint32_t stack_size) - : thread_(&Actor::threadHandler_, this, name, priority, stack_size), + Actor(const std::uint32_t queue_size, ActorThread* thread) + : IActor(thread), msg_queue_(xQueueCreate(queue_size, sizeof(value_type))), signal_(this) { assert(msg_queue_); @@ -40,6 +74,23 @@ public: virtual ~Actor() {} + void doWork() override + { + value_type data{}; + + const BaseType_t got = xQueueReceive(msg_queue_, &data, 0); + + if (got == pdTRUE) + { + std::visit(Visitor_{this}, data); + } + } + + bool hasWork() override + { + return uxQueueMessagesWaiting(msg_queue_) > 0; + } + template struct Signal : Signallable { @@ -84,11 +135,7 @@ public: return &signal_; } -protected: - virtual void init() = 0; - private: - PrimitiveThread thread_; QueueHandle_t msg_queue_; struct Visitor_ @@ -108,44 +155,17 @@ private: } }; - void operator()() - { - init(); - - value_type data{}; - - while (true) - { - const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY); - - if (got == pdTRUE) - { - std::visit(Visitor_{this}, data); - } - } - } - - static void threadHandler_(void* d) - { - auto* dd = static_cast*>(d); - (*dd)(); - } - Signal signal_; }; template -class Actor +class Actor : public IActor { public: using value_type = void; - Actor(const std::uint32_t queue_size, const char* name, const osPriority_t priority, const std::uint32_t stack_size) - : thread_([](void* d) { - auto* dd = static_cast*>(d); - (*dd)(); - }, - this, name, priority, stack_size), + Actor(const std::uint32_t queue_size, ActorThread* thread) + : IActor(thread), msg_queue_(xQueueCreate(queue_size, sizeof(int))), signal_(*this) { assert(msg_queue_); @@ -153,36 +173,32 @@ public: virtual ~Actor() {} + void doWork() override + { + int data{}; + + const BaseType_t got = xQueueReceive(msg_queue_, &data, 0); + + if (got == pdTRUE) + { + auto* crtp = static_cast(this); + crtp->onSignal(); + } + } + + bool hasWork() override + { + return uxQueueMessagesWaiting(msg_queue_) > 0; + } + Signallable* getSignal() { return &signal_; } -protected: - virtual void init() = 0; - private: - PrimitiveThread thread_; QueueHandle_t msg_queue_; - void operator()() - { - init(); - - int data; - - while (true) - { - const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY); - - if (got == pdTRUE) - { - auto* crtp = static_cast(this); - crtp->onSignal(); - } - } - } - friend struct Signal_; struct Signal_ : Signallable diff --git a/Threads/Inc/threads_actor_thread.hpp b/Threads/Inc/threads_actor_thread.hpp new file mode 100644 index 0000000..aa43135 --- /dev/null +++ b/Threads/Inc/threads_actor_thread.hpp @@ -0,0 +1,43 @@ +/* + * threads_actor_thread.hpp + * + * Created on: Sep 19, 2021 + * Author: erki + */ + +#ifndef THREADS_ACTOR_THREAD_HPP_ +#define THREADS_ACTOR_THREAD_HPP_ + +#include + +namespace Threads +{ + +class IActor; + +class ActorThread : PrimitiveThread +{ +public: + ActorThread() = delete; + ActorThread(const ActorThread&) = delete; + ActorThread(ActorThread&&) = delete; + + ActorThread(const char* name, const osPriority_t priority, const std::uint32_t stack_size) + : PrimitiveThread(&ActorThread::run_, this, name, priority, stack_size) + { } + +private: + friend class IActor; + + static void run_(void* data); + + void acceptActor_(IActor* actor); + void removeActor_(IActor* actor); + + std::array actors_; +}; + +} + + +#endif /* THREADS_ACTOR_THREAD_HPP_ */ diff --git a/Threads/Src/threads_actor_thread.cpp b/Threads/Src/threads_actor_thread.cpp new file mode 100644 index 0000000..7711228 --- /dev/null +++ b/Threads/Src/threads_actor_thread.cpp @@ -0,0 +1,69 @@ +/* + * threads_actor_thread.cpp + * + * Created on: Sep 25, 2021 + * Author: erki + */ + +#include "threads_actor_thread.hpp" + +#include + +#include "threads_actor.hpp" + +namespace Threads +{ + +void ActorThread::run_(void* data) +{ + auto* t = reinterpret_cast(data); + + for (IActor* p : t->actors_) + { + if (p) + p->init(); + } + + while (true) + { + bool remainingWork = false; + + for (IActor* p : t->actors_) + { + if (p && p->hasWork()) + { + p->doWork(); + remainingWork = remainingWork || p->hasWork(); + t->yield(); + } + } + + if (!remainingWork) + { + const bool unused = t->notifyWait(portMAX_DELAY); + (void)unused; + } + } +} + +void ActorThread::acceptActor_(IActor* actor) +{ + auto it = std::find(actors_.begin(), actors_.end(), nullptr); + + if (it == actors_.end()) + return; + + *it = actor; +} + +void ActorThread::removeActor_(IActor* actor) +{ + auto it = std::find(actors_.begin(), actors_.end(), actor); + + if (it == actors_.end()) + return; + + *it = nullptr; +} + +}