Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
ThreadPool.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** The Plazza
4** File description:
5** ThreadPool.cpp, ThreadPool class implementation
6*/
7
8/*
9** MIT License
10**
11** Copyright (c) 2025 Robin Toillon
12**
13** Permission is hereby granted, free of charge, to any person obtaining
14** a copy of this software and associated documentation files (the
15** "Software"), to deal in the Software without restriction, including
16** without limitation the rights to use, copy, modify, merge, publish,
17** distribute, sublicense, and/or sell copies of the Software, and to
18** permit persons to whom the Software is furnished to do so, subject to
19** the following conditions:
20**
21** The above copyright notice and this permission notice shall be
22** included in all copies or substantial portions of the Software.
23**
24** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31*/
32
45#include "RType/Assert.hpp"
46#include "RType/Logger.hpp"
48
49#include <format>
50#include <exception>
51
52namespace rtp::thread
53{
54
56 // Public API
58
59 auto ThreadPool::create(size_t numThreads)
60 -> std::expected<std::unique_ptr<ThreadPool>, rtp::Error>
61 {
62 constexpr std::string_view fmt{"ThreadPool init failed: {}"};
63
64 if (numThreads == 0)
65 return std::unexpected{
67 fmt, "number of threads must be at least 1")};
68
69 try {
70 std::unique_ptr<ThreadPool> pool{new ThreadPool{}};
71
72 pool->start(numThreads);
73 log::info("ThreadPool initialized successfully with {} workers.",
74 numThreads);
75
76 return pool;
77
78 } catch (const std::system_error &e) {
79 return std::unexpected{
81 fmt, e.what())};
82 } catch (...) {
83 return std::unexpected{Error::failure(ErrorCode::Unknown,
84 fmt, "unknown error")};
85 }
86 }
87
89 {
90 {
91 std::unique_lock<std::mutex> lock(this->_queueMutex);
92 this->_stop = true;
93
94 RTP_VERIFY(this->_tasks.empty(),
95 "ThreadPool destroyed with {} pending tasks discarded!",
96 this->_tasks.size());
97 }
98 this->_condition.notify_all();
99 }
100
102 // Private API
104
105 void ThreadPool::start(size_t numThreads)
106 {
107 for (size_t i = 0; i < numThreads; ++i)
108 this->_workers.emplace_back([this] (std::stop_token st)
109 {
110 this->workerThread(st);
111 });
112 }
113
114 void ThreadPool::workerThread(std::stop_token stopToken) noexcept
115 {
116 while (true) {
117 std::move_only_function<void(void)> task;
118 {
119 std::unique_lock<std::mutex> lock(this->_queueMutex);
120
121 this->_condition.wait(lock, [this, st = stopToken](void) {
122 return this->_stop || st.stop_requested()
123 || !this->_tasks.empty();
124 });
125 if ((stopToken.stop_requested() || this->_stop) &&
126 this->_tasks.empty()) [[unlikely]]
127 break;
128 if (this->_tasks.empty()) [[unlikely]]
129 continue;
130 RTP_ASSERT(!this->_tasks.empty(),
131 "Worker: Try to pop from empty queue (Logic Error)");
132
133 task = std::move(this->_tasks.front());
134 this->_tasks.pop();
135 }
136
137 RTP_ASSERT(task, "Worker: Popped an invalid/null task function!");
138
139 try {
140 task();
141 } catch (const std::exception &e) {
142 log::error("Exception in worker thread: {}", e.what());
143 } catch (...) {
144 log::error("Unknown exception in worker thread");
145 }
146 }
147 }
148}
Assertion and verification macros for runtime checks.
#define RTP_VERIFY(condition, msg,...)
Verification macro (Debug mode)
Definition Assert.hpp:130
#define RTP_ASSERT(condition, msg,...)
Assertion macro (Debug mode)
Definition Assert.hpp:113
Logger declaration with support for multiple log levels.
ThreadPool class declaration.
Comprehensive error object with severity and retry tracking.
Definition Error.hpp:156
static auto failure(ErrorCode code, std::format_string< Args... > fmt, Args &&...args) -> Error
Create a failure-level error.
ThreadPool class for managing a pool of threads.
bool _stop
Flag indicating whether the ThreadPool is stopping.
void workerThread(std::stop_token stopToken) noexcept
The worker thread function that continuously processes tasks.
std::mutex _queueMutex
Mutex for synchronizing access to the task queue.
static auto create(size_t numThreads) -> std::expected< std::unique_ptr< ThreadPool >, rtp::Error >
Creates a ThreadPool with the specified number of threads.
std::vector< std::jthread > _workers
Vector of worker threads.
void start(size_t numThreads)
Starts the worker threads in the pool.
~ThreadPool() noexcept
Destroys the ThreadPool, ensuring all threads are joined and resources are released.
std::condition_variable _condition
Condition variable for notifying worker threads.
std::queue< std::move_only_function< void(void)> > _tasks
Queue of tasks to be executed.
void error(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an error message.
void info(LogFmt< std::type_identity_t< Args >... > fmt, Args &&...args) noexcept
Log an informational message.
@ InvalidParameter
Invalid function parameter provided.
@ InternalRuntimeError
Internal runtime error.
@ Unknown
Unknown or unspecified error.