Files d'attente et tâches de fond en C++ : écrivez de l'asynchrone sans douleur

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi ton programme ralentit et comment y remédier

\n\n

Imagine : tu as écrit un super analyseur en C++ qui doit traiter 10 000 URL. Tu le lances, tu vas chercher un café, tu reviens — et il charge encore le premier site. Ça te dit quelque chose ? Le problème, c'est que le programme fonctionne de manière synchrone : pendant qu'une requête est exécutée, les autres attendent leur tour, comme dans un grand magasin soviétique.

\n\n

Dans le monde moderne, les utilisateurs ne pardonnent pas les ralentissements. Si un serveur répond en plus de 200 ms — tu perds des clients. Mais comment faire fonctionner C++ plus rapidement sans tout réécrire ? La réponse — les files d'attente et les tâches de fond. Ce n'est pas qu'un terme à la mode, mais un modèle fondamental utilisé dans le noyau Linux, les moteurs de jeux et les services à forte charge.

\n\n

Dans cet article, nous allons voir comment fonctionnent les files d'attente de tâches en C++, écrire notre propre thread pool simple et apprendre à traiter des données en arrière-plan sans conditions de course ni interblocages. Prêt à améliorer ton code ? C'est parti.

\n\n

Qu'est-ce qu'une file d'attente de tâches et pourquoi en a-t-on besoin

\n\n

Une file d'attente de tâches (task queue) est une structure de données qui fonctionne selon le principe FIFO (First In, First Out). Imagine un tapis roulant : tu ajoutes des tâches à une extrémité, et les threads d'exécution les récupèrent à l'autre. C'est la base du modèle Producer-Consumer (producteur-consommateur).

\n\n

Pourquoi en a-t-on besoin en C++ ? Voici trois raisons principales :

\n\n
    \n
  • Traitement parallèle — plusieurs threads prennent simultanément des tâches de la file, accélérant le travail plusieurs fois.
  • \n
  • Asynchrone — le thread principal n'est pas bloqué, il continue à accepter de nouvelles requêtes ou à mettre à jour l'interface.
  • \n
  • Équilibrage de charge — si une tâche est lourde, d'autres threads prennent les tâches légères, et le système ne se bloque pas.
  • \n
\n\n

Par exemple, un serveur web en C++ peut placer les requêtes HTTP entrantes dans une file d'attente, et un pool de threads les traite en parallèle. Pendant qu'un thread analyse du JSON, un autre écrit dans la base de données — et tout cela sans bloquer la boucle principale.

\n\n

Écrire une file d'attente simple en C++ à partir de zéro

\n\n

Commençons par un exemple de base. La bibliothèque standard C++ contient std::queue, mais pour le multithreading, il faut l'envelopper dans une classe protégée. Voici une implémentation minimale d'une file d'attente thread-safe :

\n\n
#include <queue>\n#include <mutex>\n#include <condition_variable>\n#include <functional>\n#include <thread>\n\nclass ThreadSafeQueue {\nprivate:\n    std::queue<std::function<void()>> tasks;\n    std::mutex mtx;\n    std::condition_variable cv;\n\npublic:\n    void push(std::function<void()> task) {\n        std::lock_guard<std::mutex> lock(mtx);\n        tasks.push(task);\n        cv.notify_one();  // Réveille un thread en attente\n    }\n\n    std::function<void()> pop() {\n        std::unique_lock<std::mutex> lock(mtx);\n        cv.wait(lock, [this] { return !tasks.empty(); });\n        auto task = tasks.front();\n        tasks.pop();\n        return task;\n    }\n};\n
\n\n

Ici, nous utilisons std::mutex pour protéger l'accès à la file et std::condition_variable pour que les threads ne gaspillent pas le processeur en attendant de nouvelles tâches. Lorsqu'une tâche apparaît, nous réveillons un thread avec notify_one().

\n\n

Mais ce n'est que la moitié du travail. Nous avons besoin d'un pool de threads (thread pool) qui exécutera ces tâches.

\n\n

Créer un pool de threads : le cœur des tâches de fond

\n\n

Un pool de threads est un ensemble de threads créés à l'avance qui attendent du travail. Au lieu de créer et de détruire des threads pour chaque tâche (ce qui est coûteux), nous les réutilisons. Voici une implémentation classique :

\n\n
class ThreadPool {\nprivate:\n    std::vector<std::thread> workers;\n    ThreadSafeQueue queue;\n    bool stop = false;\n\n    void worker_loop() {\n        while (!stop) {\n                

Blogs

Book Recommendations