ThreadPool.cpp h - JulianKerignard/ProjetJeuDeLaVie_POO GitHub Wiki
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <future>
// Classe ThreadPool pour la gestion des threads
class ThreadPool {
private:
std::vector<std::thread> workers; // Vecteur de threads
std::queue<std::function<void()>> tasks; // Queue de tâches
std::mutex queue_mutex; // Mutex pour synchroniser l'accès à la queue
std::condition_variable condition; // Condition variable pour la synchronisation
bool stop; // Indicateur pour arrêter le pool de threads
public:
// Constructeur explicite pour initialiser le pool avec un certain nombre de threads
explicit ThreadPool(size_t threads);
// Destructeur
~ThreadPool();
// Ajouter une nouvelle tâche dans le pool
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args) -> std::future<typename std::invoke_result<F, Args...>::type>;
// Arrêter tous les threads
void shutdown();
};
// Implémentation des templates
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::invoke_result<F, Args...>::type> {
using return_type = typename std::invoke_result<F, Args...>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
if (stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
#endif // THREADPOOL_H
-
Classe
ThreadPool
:-
Gère un pool de threads pour exécuter des tâches asynchrones.
-
Membres privés :
-
std::vector<std::thread> workers
: Vecteur de threads. -
std::queue<std::function<void()>> tasks
: Queue de tâches à exécuter par les threads. -
std::mutex queue_mutex
: Mutex pour synchroniser l'accès à la queue de tâches. -
std::condition_variable condition
: Variable conditionnelle pour gérer la synchronisation. -
bool stop
: Indicateur pour arrêter le pool de threads.
-
-
Membres publics :
-
explicit ThreadPool(size_t threads)
: Constructeur qui initialise le pool avec un certain nombre de threads. -
~ThreadPool()
: Destructeur qui arrête tous les threads. -
template<class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::invoke_result<F, Args...>::type>
: Ajoute une nouvelle tâche dans le pool et retourne unstd::future
pour obtenir le résultat de la tâche. -
void shutdown()
: Arrête tous les threads et nettoie le pool.
-
-
-
ThreadPool(size_t threads) :
- Initialise le pool de threads avec le nombre spécifié de threads. Chaque thread exécute les tâches en file d'attente jusqu'à ce que le pool soit arrêté.
ThreadPool::ThreadPool(size_t threads) : stop(false) {
for (size_t i = 0; i < threads; ++i)
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock,
[this]{ return this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
-
void shutdown()
- Arrête tous les threads en signalant la condition variable et attend que tous les threads se terminent.
void ThreadPool::shutdown() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker : workers)
worker.join();
}
-
ThreadPool::~ThreadPool()
- Destructeur qui appelle
shutdown()
pour arrêter tous les threads proprement avant de détruire l'objet.
- Destructeur qui appelle
ThreadPool::~ThreadPool() {
shutdown();
}
-
template<class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::invoke_result<F, Args...>::type>
- Ajoute une nouvelle tâche dans le pool et retourne un
std::future
pour obtenir le résultat de la tâche. - Utilise un
std::packaged_task
pour encapsuler la tâche et obtenir unstd::future
.
- Ajoute une nouvelle tâche dans le pool et retourne un
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::invoke_result<F, Args...>::type> {
using return_type = typename std::invoke_result<F, Args...>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
if (stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
-
Constructeur :
- Le constructeur initialise le pool de threads et démarre chaque thread qui attendra une tâche dans la queue des tâches.
- La variable
stop
est utilisée pour indiquer quand arrêter le pool de threads.
-
shutdown() :
- La méthode
shutdown
arrête tous les threads en signalant la condition variable pour réveiller tous les threads qui attendent. Elle joint ensuite tous les threads pour s'assurer qu'ils se terminent proprement.
- La méthode
-
Destructeur :
- Le destructeur appelle
shutdown
pour arrêter le pool de threads proprement avant la destruction de l'objet.
- Le destructeur appelle
-
enqueue() :
- La méthode
enqueue
ajoute une nouvelle tâche à la queue de tâches. Elle utilisestd::packaged_task
pour encapsuler la tâche et obtenir unstd::future
qui peut être utilisé pour obtenir le résultat de la tâche. - Si le pool de threads est déjà arrêté, une exception est lancée.
- La méthode