2010-12-09 4 views
1

J'ai POSIX à l'esprit pour la mise en œuvre, même si cette question est plus sur l'architecture.Comment configurer et gérer plusieurs threads persistants?

Je pars d'une boucle de mise à jour qui a plusieurs tâches principales à faire. Je peux regrouper ces tâches en quatre ou cinq tâches principales qui ont des besoins d'accès mémoire communs. C'est mon idée de rompre ces travaux dans leurs propres discussions et les faire terminer un cycle de "mise à jour" et de dormir jusqu'à la prochaine image.

Mais comment synchroniser? Si je détache quatre ou cinq fils au début de chaque cycle, les faire courir une fois, mourir, puis détacher encore 4-5 fils à chaque passage? Cela semble cher.

Il semble plus raisonnable de créer ces threads une fois, et de les mettre en veille jusqu'à ce qu'un appel synchronisé le réveille.

Est-ce une sage approche? Je suis ouvert à accepter des réponses à partir de simples idées à des implémentations de toute nature.

EDIT: sur la base des réponses à ce jour, je voudrais ajouter:

    concurrency
  • est souhaitée
  • ces threads de travail sont destinés à fonctionner à des durées très courtes < 250ms
  • le travail fait par chaque thread sera toujours le même
  • Je considère 4-5 threads, 20 étant une limite dure.

Répondre

1

Si vous avez toujours le même travail à faire à chaque cycle, et que vous devez attendre que tout le travail se termine avant le prochain cycle, alors vous pensez à la bonne solution.

Vous aurez besoin de certains objets de synchronisation: un "sémaphore de début de trame", un "sémaphore de fin de trame" et un "événement de fin de trame". Si vous avez des tâches n indépendantes de chaque trame, commencer fils de n, avec des boucles qui ressemblent à ceci (pseudo-code):

while true: 
    wait on "start of frame semaphore" 
    <do work> 
    enter lock 
    decrement "worker count" 
    if "worker count" = 0 then set "end of frame event" 
    release lock 
    wait on "end of frame semaphore" 

Vous pouvez alors une course de fil de commande:

while true: 
    set "worker count" to n 
    increment "start of frame semaphore" by n 
    wait on "end of frame event" 
    increment "end of frame semaphore" by n 

Cela fonctionne bien pour petit n. Si le nombre de tâches dont vous avez besoin pour terminer chaque cycle devient important, vous voudrez probablement utiliser un pool de threads couplé à une file d'attente de tâches, afin de ne pas surcharger le système de threads. Mais il y a plus de complexité avec cette solution, et avec la complexité du thread est l'ennemi.

+0

salut john. Je pense que cela ressemble à une approche raisonnable pour mes besoins. Je ne me vois pas dépasser 12 threads à ce sujet. d'autant plus que j'ai l'option de consolider les threads si N devient trop grand. Pour être clair, dans cette implémentation, les threads de travail sont toujours actifs, mais seul un sémaphore détachera le code? ou est-ce que la librairie posix mettra le fil en pause, puis réactivera le fil sur le sémaphore? la boucle du contrôleur définit simplement l'état du sémaphore, correct? – bitcruncher

+0

Je ne suis pas sûr de ce que vous entendez par "actif". L'attente sur un sémaphore devrait amener le thread à se mettre en veille jusqu'à ce que le sémaphore soit incrémenté. Le thread ne doit pas utiliser les ressources du processeur ou du planificateur tant que les sémaphores ne sont pas libérés. Le thread du contrôleur est juste là pour définir l'état du sémaphore. Avec une complexité supplémentaire, ce thread peut être éliminé, mais la complexité est l'ennemi, et généralement vous avez quelque chose d'autre à faire pour ce thread. :) –

1

Le mieux est probablement d'utiliser une file d'attente de tâches.

Les files d'attente de tâches peuvent être considérées comme des tâches en attente d'envoi d'un travail. Si plusieurs sont envoyés en même temps, ils sont exécutés dans l'ordre FIFO. De cette façon, vous conservez 4-5 threads, et chacun d'eux exécute le travail que vous les alimentez, sans avoir besoin de détacher un nouveau thread pour chaque travail.

Le seul problème est que je ne connais pas beaucoup d'implémentations de files d'attente de tâches dans C. Apple a Grand Central Dispatch qui fait exactement cela; FreeBSD en a aussi une implémentation. Sauf ceux-là, je n'en connais aucun autre. (Je n'ai pas l'air très fort, cependant.)

2

Cela dépend de la granularité des tâches que les threads effectuent. S'ils exécutent de longues tâches (par exemple une seconde ou plus), le coût de création et de destruction des threads est négligeable par rapport au travail effectué par les threads. Je vous recommande donc de garder les choses simples et de créer les threads à la demande. Inversement, si vous avez des tâches très courtes (par exemple moins de 10-100 ms environ), vous commencerez certainement à remarquer le coût de création et de destruction de beaucoup de threads. Dans ce cas, oui, vous devez créer les threads une seule fois et les laisser dormir jusqu'à ce que le travail arrive pour eux. Vous devrez utiliser une sorte de condition variable (par exemple, pthread_cond_t) pour cela: le thread attend la variable de condition, et lorsque le travail arrive, vous signalez la variable de condition.

+0

+1 pour cela. J'aurais accepté votre réponse, mais John a proposé une mise en œuvre plus proche de mes besoins. – bitcruncher

0

Votre idée est appelée pool de threads. Ils se trouvent dans WinAPI, Intel TBB et le Visual Studio ConcRT, je ne connais pas grand-chose à POSIX et ne peux donc pas vous aider, mais ils sont une excellente structure avec de nombreuses propriétés désirables, comme une excellente mise à l'échelle. être séparé.

Cependant, je ne voudrais pas banaliser le temps que le travail prend.Si vous avez cinq tâches et que vous avez un problème de performance si désespéré que plusieurs threads sont la clé, la création des threads est presque certainement un problème négligeable.

+0

merci, j'apprécie l'avertissement. bien que dans ce cas, je ne casse pas une tâche parce que cela prend trop de temps. J'essaie de segmenter différentes zones qui sont les principaux candidats pour la concurrence. – bitcruncher

+0

@bitcruncher: Concurrency a un seul et unique objectif: la performance. Si vous n'avez pas besoin de la performance, vous n'avez pas besoin de concurrence. – Puppy

+0

oui, bien sûr. Je suppose que ce que j'essaie de dire, c'est qu'à ce stade de ma mise en œuvre, je ne tente pas de refactoriser une tâche monolithique existante. Je prépare le terrain pour de futures tâches qui partagent des espaces de mémoire similaires et devront être exécutées le plus rapidement possible. – bitcruncher

Questions connexes