R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
ThreadPool.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by hugo on 06/12/2025
4** File description:
5** ThreadPool.cpp
6*/
7
10
11namespace server {
12
13 ThreadPool::ThreadPool(size_t threadCount) : _threadCount(threadCount) {}
14
16 try {
18 // jthread automatically requests stop and joins in its destructor
19 } catch (const std::exception &e) {
20 LOG_ERROR("ThreadPool destructor caught exception: ", e.what());
21 }
22 }
23
25 if (!_workers.empty()) {
26 LOG_WARNING("ThreadPool already running");
27 return; // Already started
28 }
29
30 LOG_INFO("Starting ThreadPool with ", _threadCount, " workers...");
31
32 _workers.reserve(_threadCount);
33 for (size_t i = 0; i < _threadCount; ++i) {
34 // jthread automatically passes stop_token to the lambda
35 _workers.emplace_back([this, i](std::stop_token stopToken) {
36 LOG_DEBUG("Worker thread ", i, " started (TID: ", std::this_thread::get_id(), ")");
37 _workerLoop(stopToken);
38 LOG_DEBUG("Worker thread ", i, " exiting");
39 });
40 }
41
42 LOG_INFO("✓ ThreadPool started with ", _threadCount, " workers");
43 }
44
46 if (_workers.empty()) {
47 return; // Already stopped
48 }
49
50 LOG_INFO("Stopping ThreadPool...");
51
52 // Request stop for all worker threads
53 for (auto &worker : _workers) {
54 worker.request_stop();
55 }
56
57 // Wake up all workers by pushing poison pills (in case they're blocked on pop())
58 for (size_t i = 0; i < _threadCount; ++i) {
59 _taskQueue.push(nullptr);
60 }
61
62 // jthread joins automatically in destructor, but we join explicitly here for clean shutdown
63 _workers.clear(); // This will trigger join on all jthreads
64
65 LOG_INFO("✓ ThreadPool stopped");
66 }
67
69 if (_workers.empty()) {
70 LOG_WARNING("Enqueuing task to stopped ThreadPool - task will not execute");
71 return;
72 }
73
74 if (!task) {
75 LOG_WARNING("Attempted to enqueue null task");
76 return;
77 }
78
79 _taskQueue.push(std::move(task));
80 }
81
82 size_t ThreadPool::size() const {
83 return _threadCount;
84 }
85
86 void ThreadPool::_workerLoop(std::stop_token stopToken) {
87 while (!stopToken.stop_requested()) {
88 // Block until a task is available
89 Task task = _taskQueue.pop();
90
91 // nullptr is poison pill (shutdown signal)
92 if (!task) {
93 break;
94 }
95
96 try {
97 task();
98 } catch (const std::exception &e) {
99 LOG_ERROR("Worker thread caught exception: ", e.what());
100 } catch (...) {
101 LOG_ERROR("Worker thread caught unknown exception");
102 }
103 }
104 }
105
106} // namespace server
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_DEBUG(...)
Definition Logger.hpp:180
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
T pop()
Pop an item, blocking until one is available.
void push(T item)
Push an item to the queue.
std::function< void()> Task
size_t size() const override
Get the number of threads in the pool.
~ThreadPool() override
std::vector< std::jthread > _workers
void stop() override
Stop all threads and clean up resources.
void _workerLoop(std::stop_token stopToken)
Worker thread main loop Continuously pulls tasks from the queue and executes them.
void enqueue(Task task) override
Enqueue a task to be executed by the thread pool.
void start() override
Start all threads in the pool.
ThreadPool(size_t threadCount)
ThreadSafeQueue< Task > _taskQueue