111 lines
2.6 KiB
C++
111 lines
2.6 KiB
C++
#pragma once
|
|
|
|
#include "Core.hpp"
|
|
#include "Utilities.hpp"
|
|
#include <thread>
|
|
#include <mutex>
|
|
#include <condition_variable>
|
|
#include <vector>
|
|
#include <memory>
|
|
#include <atomic>
|
|
|
|
namespace reactor {
|
|
|
|
class EventLoopThread : public NonCopyable
|
|
{
|
|
private:
|
|
std::thread thread_;
|
|
EventLoop* loop_;
|
|
std::mutex mutex_;
|
|
std::condition_variable cond_;
|
|
std::string name_;
|
|
|
|
void threadFunc()
|
|
{
|
|
LOG_DEBUG << "EventLoopThread '" << name_ << "' starting";
|
|
EventLoop loop;
|
|
{
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
loop_ = &loop;
|
|
cond_.notify_one();
|
|
}
|
|
|
|
loop.loop();
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
loop_ = nullptr;
|
|
LOG_DEBUG << "EventLoopThread '" << name_ << "' finished";
|
|
}
|
|
|
|
public:
|
|
explicit EventLoopThread(const std::string& name = "EventLoopThread")
|
|
: loop_(nullptr), name_(name)
|
|
{
|
|
thread_ = std::thread([this]() { threadFunc(); });
|
|
std::unique_lock<std::mutex> lock(mutex_);
|
|
cond_.wait(lock, [this]() { return loop_ != nullptr; });
|
|
LOG_INFO << "EventLoopThread '" << name_ << "' initialized";
|
|
}
|
|
|
|
~EventLoopThread()
|
|
{
|
|
if (loop_) {
|
|
loop_->quit();
|
|
thread_.join();
|
|
}
|
|
LOG_INFO << "EventLoopThread '" << name_ << "' destroyed";
|
|
}
|
|
|
|
EventLoop* getLoop() { return loop_; }
|
|
const std::string& name() const { return name_; }
|
|
};
|
|
|
|
class EventLoopThreadPool : public NonCopyable
|
|
{
|
|
private:
|
|
std::vector<std::unique_ptr<EventLoopThread>> threads_;
|
|
std::vector<EventLoop*> loops_;
|
|
std::atomic<size_t> next_;
|
|
std::string baseThreadName_;
|
|
|
|
public:
|
|
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<EventLoopThread>(threadName);
|
|
loops_.push_back(thread->getLoop());
|
|
threads_.push_back(std::move(thread));
|
|
}
|
|
|
|
LOG_INFO << "EventLoopThreadPool created with " << numThreads << " threads";
|
|
}
|
|
|
|
~EventLoopThreadPool()
|
|
{
|
|
LOG_INFO << "EventLoopThreadPool destroying " << threads_.size() << " threads";
|
|
}
|
|
|
|
EventLoop* getNextLoop()
|
|
{
|
|
if (loops_.empty()) {
|
|
LOG_WARN << "EventLoopThreadPool has no loops available";
|
|
return nullptr;
|
|
}
|
|
|
|
size_t index = next_++ % loops_.size();
|
|
LOG_TRACE << "EventLoopThreadPool returning loop " << index;
|
|
return loops_[index];
|
|
}
|
|
|
|
std::vector<EventLoop*> getAllLoops() const { return loops_; }
|
|
size_t size() const { return loops_.size(); }
|
|
|
|
const std::string& getBaseName() const { return baseThreadName_; }
|
|
};
|
|
|
|
} // namespace reactor
|