Thread Pool - C++ - Programmation
Marsh Posté le 16-07-2012 à 17:07:03
Tes locks devraient être faits en RAII, tu verras, ca allège pas mal le code dès que tu as des fonctions un peu complexes.
Je ne suis pas fan du while(true) dans la fonction treat. Globalement, killer des threads, c'est pas très joli, et avec la manière dont c'est architecturé, là, t'as pas trop le choix.
Marsh Posté le 16-07-2012 à 19:08:35
theshockwave a écrit : Tes locks devraient être faits en RAII, tu verras, ca allège pas mal le code dès que tu as des fonctions un peu complexes. Je ne suis pas fan du while(true) dans la fonction treat. Globalement, killer des threads, c'est pas très joli, et avec la manière dont c'est architecturé, là, t'as pas trop le choix. |
hello !
merci pour tes réponses, pour les locks/unlocks en fait j'ai eu un peu la flemme de les faire en RAII
sinon, comment je pourrais architecturer différement pour ne pas avoir à killer mes threads ...? il y a une technique pour ça ?
autrement, comment on choisis le nombre de threads ? J'ai essayé avec plusieurs valeurs, même jusqu'à 512 lol. ça doit être combien généralement ..?
merci
ps : par ailleurs, pourquoi les "cout" s'affichent souvent un peu n'importe comment, alors que pas les printf ? (pour les mêmes messages)
Marsh Posté le 16-07-2012 à 19:20:38
Ca dépend complètement de tes besoins.
Si tu vois ton système comme un job manager (Edit : micro tâches pour faire une distributions en découpant au max tes lourdes tâches), tu vas probablement vouloir avoir autant de threads à dispositions que tu as de threads hardware sur ta machine.
Si tu vois ca comme juste la possibilité de faire du "Fire and Forget" sur tes tâches (Edit : tâches lourdes) pour un max de client, peut-être que tu en voudras plus quitte à ralentir ta machine juste pour que le boulot pour chaque client commence au plus tôt ...
Dans le premier cas, tu voudras aussi probablement une interface qui te permette d'ajouter N tâches d'un coup. Dans l'autre, probablement pas.
Edit : les cas que je liste ne sont pas nécessairement les seuls que tu rencontreras, évidemment.
Marsh Posté le 17-07-2012 à 10:28:31
theshockwave a écrit : Ca dépend complètement de tes besoins. |
hello !
ok merci pour tes réponses. Quand tu parles de "threads hardware", ce sont en fait les coeur du CPU non ?
sinon, à partir de quand une tache deviens "lourde" ?
Marsh Posté le 17-07-2012 à 11:20:48
in_your_phion a écrit : |
Threads hardware, c'est pas tout à fait coeur, mais presque. Sur du intel, avec hyperthreading, tu as deux threads hardware par coeur.
Encore une fois, la "lourdeur" de la tâche dépend du contexte. Suivant les contraintes que tu as en terme de temps (obligation de terminer tes tâches dans un délais imparti) ou d'architecture (genre rentabiliser les SPUs d'un cell qui n'ont pas d'accès direct à la mémoire) ta notion de "lourdeur" va varier.
J'ai tendance à penser qu'un système de jobs "légers", ca va être quand tu as besoin que tous tes jobs aient terminé pour pouvoir en lancer de nouveaux (à peu de choses près) alors que le système de tâches "lourdes", ca va plus être du fire and forget ... Ca termine quand ca peut et tu en tiens compte à ce moment là.
Exemple : dans un jeu vidéo, tu vas sans doute avoir une phase de mise à jour des positions de tes objets que tu vas pouvoir paralléliser, et tu vas avoir une attente forte dessus pour pouvoir afficher le résultat à l'écran. Là, clairement, on est dans un contexte de tâches "légères" (c'est critique si ca prend plus de 2 ou 3 millisecondes). Par contre, une requête d'IA, si c'est pas immédiat, c'est peut-être pas si grave, du coup c'est "lourd" (quelques dizaines de millisecondes)
Dans le cas des tâches "légères", tu veux clairement faire correspondre tes threads disponibles à tes ressources matérielles parce que c'est critique.
Dans le cas des tâches "lourdes", tu veux juste avoir un pool de threads sous le coude pour ne pas payer le coût de la création d'un thread à chaque lancement de tâche.
Marsh Posté le 17-07-2012 à 11:32:44
Autre détail : tu as des mutex pour protéger ta file de tâches. Normalement, tu dois pouvoir faire une "lock-free queue". En terme de performance, ca peut changer la vie.
Si tu vires ce mutex, la condition ne sera plus utilisable, tu n'auras plus besoin que d'un système de signal basique et tes threads attendront ce signal quand la liste de tâches est vide. Ton manager pourra réveiller tous les threads ou juste ceux qu'ils choisi en fonction de ce qui arrive à traiter.
Marsh Posté le 17-07-2012 à 12:07:27
theshockwave a écrit :
J'ai tendance à penser qu'un système de jobs "légers", ca va être quand tu as besoin que tous tes jobs aient terminé pour pouvoir en lancer de nouveaux (à peu de choses près) alors que le système de tâches "lourdes", ca va plus être du fire and forget ... Ca termine quand ca peut et tu en tiens compte à ce moment là. Exemple : dans un jeu vidéo, tu vas sans doute avoir une phase de mise à jour des positions de tes objets que tu vas pouvoir paralléliser, et tu vas avoir une attente forte dessus pour pouvoir afficher le résultat à l'écran. Là, clairement, on est dans un contexte de tâches "légères" (c'est critique si ca prend plus de 2 ou 3 millisecondes). Par contre, une requête d'IA, si c'est pas immédiat, c'est peut-être pas si grave, du coup c'est "lourd" (quelques dizaines de millisecondes) Dans le cas des tâches "légères", tu veux clairement faire correspondre tes threads disponibles à tes ressources matérielles parce que c'est critique. |
merci bien pour toutes ces explications ! pourtant il m'avait semblé lire que le thread pool devait être utilisé pour des tâches qui ne durent pas très longtemps, mais peut être que c'est relatif ?
Par exemple, si tu as une matrice géante et que tu veux paralléliser les calculs (un thread par calcul de produit scalaire ligne x colonne), est ce qu'un thread pool est approprié ?
theshockwave a écrit : Autre détail : tu as des mutex pour protéger ta file de tâches. Normalement, tu dois pouvoir faire une "lock-free queue". En terme de performance, ca peut changer la vie. |
merci je vais essayer ça dans ce cas le signal est juste une variable partagée par les threads ? (genre un booléen ?)
Marsh Posté le 17-07-2012 à 12:38:39
in_your_phion a écrit : |
houlà, c'est toujours des threads pools, ce sont juste deux cas de figures différents qui font que tu vas pas forcément programmer ton pool de la même manière. Quoiqu'il arrive, oui, quand tu veux paralléliser c'est une bonne idée d'avoir un pool de threads, quelles que soient tes contraintes. Ton exemple de multiplication de matrices me fait plus penser à un process léger, justement, où tu vas distribuer ton calcul de manière à ce que tous tes threads hardwares tournent à 100% mais pas plus. En gros, sur ce genre de tâches, on cherche aussi à minimiser les changements de tâches des CPUs. Passer d'un contexte de thread à un autre n'est pas gratuit pour le matériel. Quand tu compares ca à une série de multiplications et additions même en flotttants, ca reste conséquent.
in_your_phion a écrit : merci je vais essayer ça dans ce cas le signal est juste une variable partagée par les threads ? (genre un booléen ?) |
Dans l'idée, c'est un booléen, oui, mais tu dois avoir un système de signal dans les pthreads, j'imagine, qui te permettra de le faire correctement. (attention à ne pas utiliser juste un signal "instantané" que tes threads risqueraient de rater mais bien quelque chose qui place un flag jusqu'à ce que ce soit resetté soit manuellement, soit implicitement par une lecture)
Marsh Posté le 17-07-2012 à 20:43:41
in_your_phion a écrit : |
Ce que je fais en général, c'est une boucle de travail dans mon thread avec une variable de controle , et je suspend mon thread pendant un temps donné s'il n'a rien à faire.
Pour le détruire, il suffit de changer la valeur de la variable de controle, de resumer le thread et de le join.
Code :
|
En espérant que ca t'aide. (j 'ai juste fait du copier coller de code pour expliquer le principe, il faut bien sur tester les valeurs retournées des appels système )
Marsh Posté le 18-07-2012 à 10:20:20
xilebo a écrit : Ce que je fais en général, c'est une boucle de travail dans mon thread avec une variable de controle , et je suspend mon thread pendant un temps donné s'il n'a rien à faire. |
Marsh Posté le 18-07-2012 à 11:03:09
xilebo a écrit : En espérant que ca t'aide. (j 'ai juste fait du copier coller de code pour expliquer le principe, il faut bien sur tester les valeurs retournées des appels système ) |
salut,
merci beaucoup pour ton code je vois mieux là ^^
en fait j'avais essayé avec ça mais ça ne marchais pas terrible pour mon code, car j'avais mis un wait sans timeout, mais avec un timeout ça devrait plus le faire
ps : j'aurais encore une autre question, est ce que faire une boucle avec des try_lock() peut être vu comme un spin lock ?
merci
Marsh Posté le 18-07-2012 à 11:09:35
in_your_phion a écrit : |
Pas besoin de timeout, il faut juste signaler ta condition. Du point de vue du threads, tu dois traiter les deux cas, soit il y a effectivement quelque chose à consommer, soit il n'y a rien et c'est peut-être qu'il faut quitter (consulte le flag correspondant)
Marsh Posté le 16-07-2012 à 12:42:18
Bonjour,
J'essaie de faire un thread pool pour voir comment ça marche.
http://en.wikipedia.org/wiki/Thread_pool_pattern
Est ce que vous pourriez me dire si mon implémentation est correcte ...?
merci par avance
les tâches font rien de spécial, j'ai juste crée ça :
Pour le thread pool, j'ai crée une classe avec une queue qui contient les taches, et un vecteur pour les n threads :
La fonction associée aux threads dépile les taches et execute la tâche courante :
voici le code complet :
ça vous parait bien ou y a t-il une erreur de design ou de conception ?
merki
Message édité par in_your_phion le 16-07-2012 à 14:59:31