#pragma once #include "Core.hpp" #include "Utilities.hpp" #include #include #include #include #include #include namespace reactor { class EventLoopThread : public NonCopyable { private: std::jthread thread_; EventLoop* loop_; std::latch readyLatch_; std::string name_; /* * The function executed by the internal thread. * It creates the EventLoop, signals readiness, and runs the loop. */ void threadFunc() { EventLoop loop; loop_ = &loop; readyLatch_.count_down(); loop.loop(); } public: /* * Constructs an EventLoopThread. * Starts a new thread and creates an EventLoop within it, * waiting until the loop is fully initialized. */ explicit EventLoopThread(const std::string& name = "EventLoopThread") : loop_(nullptr), readyLatch_(1), name_(name) { thread_ = std::jthread(&EventLoopThread::threadFunc, this); readyLatch_.wait(); LOG_INFO << "EventLoopThread '" << name_ << "' initialized"; } /* * Destructs the EventLoopThread. * Quits the event loop. The underlying jthread automatically joins. */ ~EventLoopThread() { if (loop_) { loop_->quit(); } LOG_INFO << "EventLoopThread '" << name_ << "' destroyed"; } /* * Returns the EventLoop associated with this thread. * The pointer is valid for the lifetime of the thread. */ EventLoop* getLoop() { return loop_; } /* * Returns the name of the thread. */ const std::string& name() const { return name_; } }; class EventLoopThreadPool : public NonCopyable { private: std::vector> threads_; std::vector loops_; std::atomic next_; std::string baseThreadName_; public: /* * Constructs an EventLoopThreadPool. * Creates a pool of threads, each running an EventLoop. */ explicit EventLoopThreadPool(size_t numThreads, const std::string& baseName = "EventLoopThread") : next_(0), baseThreadName_(baseName) { LOG_INFO << "Creating EventLoopThreadPool with " << numThreads << " threads"; for (size_t i = 0; i < numThreads; ++i) { std::string threadName = baseThreadName_ + "-" + std::to_string(i); auto thread = std::make_unique(threadName); loops_.push_back(thread->getLoop()); threads_.push_back(std::move(thread)); } LOG_INFO << "EventLoopThreadPool created with " << numThreads << " threads"; } /* * Destructs the thread pool. * The threads will be quit and joined automatically via their destructors. */ ~EventLoopThreadPool() { LOG_INFO << "EventLoopThreadPool destroying " << threads_.size() << " threads"; } /* * Gets the next EventLoop from the pool in a round-robin fashion. * This method is thread-safe. */ EventLoop* getNextLoop() { if (loops_.empty()) { LOG_WARN << "EventLoopThreadPool has no loops available"; return nullptr; } size_t index = next_.fetch_add(1, std::memory_order_relaxed) % loops_.size(); LOG_TRACE << "EventLoopThreadPool returning loop " << index; return loops_[index]; } /* * Returns pointers to all EventLoops in the pool. */ std::vector getAllLoops() const { return loops_; } /* * Returns the number of threads in the pool. */ size_t size() const { return loops_.size(); } /* * Returns the base name for threads in the pool. */ const std::string& getBaseName() const { return baseThreadName_; } }; }