65 votes

C #: en attente de la fin de tous les threads

Je suis en cours d'exécution dans un modèle commun dans le code que j'écris, où je dois attendre que tous les threads dans un groupe au complet, avec un délai d'attente. Le délai d'attente est censé être le temps nécessaire pour que tous les threads, donc tout simplement de faire thread.Join(timeout) pour chaque thread ne fonctionne pas, puisque le possible, le délai est de puis délai d'attente * numThreads.

Maintenant je ne quelque chose comme ce qui suit:

var threadFinishEvents = new List<EventWaitHandle>();

foreach (DataObject data in dataList)
{
    // Create local variables for the thread delegate
    var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
    threadFinishEvents.Add(threadFinish);

    var localData = (DataObject) data.Clone();
    var thread = new Thread(
        delegate()
        {
            DoThreadStuff(localData);
            threadFinish.Set();
        }
    );
    thread.Start();
}

Mutex.WaitAll(threadFinishEvents.ToArray(), timeout);

Cependant, il semble comme il devrait être simple idiome pour ce genre de chose.

26voto

Martin v. Löwis Points 61768

Je pense toujours que l'utilisation de Join est plus simple. Enregistrez l’heure de fin prévue (sous la forme Now + timeout), puis, en boucle, faites

 if(!thread.Join(End-now))
    throw new NotFinishedInTime();
 

22voto

cyberSecurity Points 2233

Avec .NET 4.0, je trouve System.Threading.Tasks beaucoup plus facile à utiliser. Voici une boucle d'attente qui fonctionne de manière fiable pour moi. Il bloque le thread principal jusqu'à ce que toutes les tâches soient terminées. Il y a aussi Task.WaitAll , mais cela n'a pas toujours fonctionné pour moi.

         for (int i = 0; i < N; i++)
        {
            tasks[i] = Task.Factory.StartNew(() =>
            {               
                 DoThreadStuff(localData);
            });
        }
        while (tasks.Any(t => !t.IsCompleted)) { } //spin wait
 

9voto

Brian Gideon Points 26683

Depuis que la question a été soulevée, je vais aller de l'avant et poster ma solution.

 using (var finished = new CountdownEvent(1)) 
{ 
  for (DataObject data in dataList) 
  {   
    finished.AddCount();
    var localData = (DataObject)data.Clone(); 
    var thread = new Thread( 
        delegate() 
        {
          try
          {
            DoThreadStuff(localData); 
            threadFinish.Set();
          }
          finally
          {
            finished.Signal();
          }
        } 
    ); 
    thread.Start(); 
  }  
  finished.Signal(); 
  finished.Wait(YOUR_TIMEOUT); 
} 
 

8voto

Omer van Kloeten Points 6268

Pourquoi ne vous contentez-vous pas de Thread.Join (timeout) et de supprimer le temps nécessaire pour rejoindre le délai d'expiration total?

 // pseudo-c#:

TimeSpan timeout = timeoutPerThread * threads.Count();

foreach (Thread thread in threads)
{
    DateTime start = DateTime.Now;

    if (!thread.Join(timeout))
        throw new TimeoutException();

    timeout -= (DateTime.Now - start);
}
 

Edit: le code est maintenant moins pseudo. Je ne comprends pas pourquoi vous modifiez une réponse -2 alors que la réponse que vous modifiez +4 est exactement la même chose, mais qu’elle est moins détaillée.

6voto

Jon Norton Points 2048

Ce n'est peut-être pas une option pour vous, mais si vous pouvez utiliser l'extension parallèle pour .NET, vous pouvez utiliser Task s au lieu de threads bruts, puis utiliser Task.WaitAll() pour les attendre. compléter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X