2009-02-27 7 views
3

Si vous avez un thread principal qui démarre deux autres threads. Quelle est la manière la plus propre de faire attendre le thread primaire pour les deux autres threads?Attendez que deux threads se terminent

Je pourrais utiliser bgndworker et sleep spinner qui vérifie les deux IsBusy des travailleurs de bgnd, mais je pense qu'il y a une meilleure façon.

EDIT Quelques autres exigences:

  • Le fil conducteur a un autre travail à faire (par exemple GUI).
  • Les deux fils donné naissance devraient pouvoir signaler les exceptions et retour résultat valeurs
+0

Voir aussi: http://stackoverflow.com/questions/540078/wait-for-pooled-threads-to-complete –

Répondre

5

Voir les réponses au this thread. J'aime this option ;-P

Forker p = new Forker(); 
p.Fork(delegate { DoSomeWork(); }); 
p.Fork(delegate { DoSomeOtherWork(); }); 
p.Join(); 

Re retour valeurs/exceptions de rapports - juste avoir chaque fourche faire cela comme un rappel à la fin de la logique ... (vous pouvez utiliser des variables capturées pour passer l'état à la fois la fourches, y compris un enregistreur partagé, etc.).

0

WaitHandle.WaitAny est votre ami. Il vous permet d'attendre sur plusieurs threads ou d'autres types d'objets à signaler.

http://msdn.microsoft.com/en-us/library/tdykks7z.aspx

EDIT:

En fait, WaitHandle.WaitAll est ce que vous voulez, pas WaitAny.

http://msdn.microsoft.com/en-us/library/system.threading.waithandle.waitall.aspx

EDIT:

La méthode join une mention est ok, mais un inconvénient est que ce n'est pas une opération complètement atomique. Cela peut ou peut ne pas être important pour vous, cependant.

+0

Dans ma situation actuelle ce n'est pas grave, mais j'essaie d'avoir une idée principale hors de chaque question afin que je puisse l'appliquer plus tard quand d'autres problèmes surviennent. Alors oui, c'est important d'une certaine manière. –

3
thread1.Join(); 
thread2.Join(); 
+0

Cela nécessite le fil vanille et ne me permet pas de bulles d'exception, etc. –

+3

C'était une excellente réponse avant d'ajouter "Exigences supplémentaires". Il doit être un utilisateur ... –

+0

Oui - peut-être une deuxième question aurait été appropriée –

10

Exemple rapide utilisant Thread.Join();

 Thread t1 = new Thread(new ThreadStart(delegate() 
     { 
      System.Threading.Thread.Sleep(2000); 
     })); 

     Thread t2 = new Thread(new ThreadStart(delegate() 
     { 
      System.Threading.Thread.Sleep(4000); 
     })); 

     t1.Start(); 
     t2.Start(); 

     t1.Join(); 
     t2.Join(); 

EDIT Une autre 3example en utilisant Wait Poignées:

  ManualResetEvent[] waitHandles = new ManualResetEvent[]{ 
      new ManualResetEvent(false), 
      new ManualResetEvent(false) 
     }; 

     Thread t1 = new Thread(new ParameterizedThreadStart(delegate(object state) 
     { 
      ManualResetEvent handle = (ManualResetEvent)state; 
      System.Threading.Thread.Sleep(2000); 
      handle.Set(); 
     })); 

     Thread t2 = new Thread(new ParameterizedThreadStart(delegate(object state) 
     { 
      ManualResetEvent handle = (ManualResetEvent)state; 
      System.Threading.Thread.Sleep(4000); 
      handle.Set(); 
     })); 

     t1.Start(waitHandles[0]); 
     t2.Start(waitHandles[1]); 

     WaitHandle.WaitAll(waitHandles); 

     Console.WriteLine("Finished"); 
+0

La deuxième exaple pourrait m'aider, je vais y jeter un oeil –

+0

Y at-il un moyen d'utiliser le resetevents avec l'arrière-plan? –

+0

Abonnez-vous à RunWorkerCompleted de BackgroundWorker qui est déclenché lorsque la tâche est terminée, annulée ou déclenche une exception –

1

En plus des autres réponses ... une alternative à "commencer à deux fils et d'attendre les deux à la fin" est « start un thread et effectuez vous-même un travail, puis attendez que l'autre thread se termine ".

Bien sûr, si vous voulez démarrer deux tâches, travaillez plus sur le thread principal et puis attendez que les deux autres threads se terminent, cela ne fonctionne pas très bien.

EDIT: Si le thread principal est un thread UI, vous ne devriez pas bloquer sur les autres threads de finition - vous devriez (IMO) les amener à rappeler au thread principal quand ils ont fini. De cette façon, vous aurez toujours une interface utilisateur réactive pendant l'exécution.

+0

Oui, point valide. Mais peut-être que j'ai trop simplifié la question. Le thread principal sera occupé à mettre à jour l'interface utilisateur afin de ne pas être dérangé par les tâches lourdes IO. –

+0

Le thread principal est un thread de la console. Il affichera un message "Waiting ..." répétitif. Mais je vous suis sur les événements qui tournent. Voir mon autre question: http://stackoverflow.com/questions/594329/define-backgroundworkers-runworkercompleted-with-an-anonymous-method Ou suis-je complètement hors piste? –

1

Vous ne pouvez pas attendre la fin et avoir GUI utilisable. La meilleure approche consiste à générer des threads et à utiliser des événements pour communiquer avec l'interface graphique. Souvenez-vous que dans le gestionnaire d'événements, vous ne pouvez pas modifier le contrôle. Plutôt que de le faire directement, utilisez la méthode Invoke.

+0

Habituellement aussi on a besoin d'informations sur l'interface graphique pour que l'utilisation des événements pour les informations de progression ne puisse pas être évitée si vous ne voulez pas que le thread soit autiste. Cette réponse est la meilleure que je puisse lire sur cette page, merci! – jdehaan

Questions connexes