2010-09-29 4 views
1

J'ai un service Windows qui a un certain nombre de threads qui doivent tous être arrêtés avant que le service s'arrête. J'utilise ce modèle pour arrêter mes fils et de signalisation qu'ils ont été arrêtés:Quelle est la meilleure façon de déterminer si les threads sont arrêtés?

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate 
{ 
    Thread1Running = true; 

    try 
    { 
     while (running) 
     { 
      AutoReset1.WaitOne(TimeSpan.FromSeconds(30.0)); 

      if (running) 
      { 
       // do stuff 
      } 
     } 
    } 
    finally 
    { 
     Thread1Running = false; 
    } 
})); 

Quand vient le temps de fermer mon service pour arrêter, je viens de faire courir à faux et appeler Set() sur tous les AutoResets là-bas. Cela signale instantanément aux threads d'arrêter de dormir ou de s'arrêter une fois qu'ils ont fini de traiter ce sur quoi ils travaillent. Cela fonctionne vraiment bien. Mais, la partie qui me rend le plus nerveux, c'est de vérifier que tout s'est arrêté. Voilà ce que je fais maintenant:

Int32 tries = 0; 
while (tries < 5 && (Thread1Running || Thread2Running || Thread3Running)) 
{ 
    tries++; 

    Thread.Sleep(TimeSpan.FromSeconds(5.0)); 
} 

La principale raison pour laquelle je n'aime pas que ce soit qu'il est temps basé, et si l'un de mes fils est au milieu d'une opération longue (ce qui est tout à fait probablement), l'arrêt peut ne pas se terminer dans les 25 secondes (et il est très important que tous ces threads soient arrêtés au moment où OnStop, où ce code est exécuté, se termine). Je ne peux pas supprimer les essais parce que si l'un de ces threads se bloque (ils ne le font pas, mais on ne sait jamais), alors je suis vraiment bloqué et le service ne s'arrêtera jamais.

Existe-t-il un meilleur moyen de vérifier que les threads ont tous cessé, de préférence ceux qui ne sont pas basés sur le temps? Ou suis-je condamné à avoir une sorte de timeout qui pourrait avoir besoin d'être beaucoup plus long (10 essais avec un sommeil de 30 secondes, peut-être)?

+0

Quelle version .NET utilisez-vous? –

+0

3.5 mais 4.0 pourrait être une option. –

Répondre

1

Je crois que la méthode générale pour faire ceci est de se joindre aux threads. Les spécificités de l'appel dépendront de la bibliothèque de threads que vous utilisez, mais en général, la méthode join bloquera jusqu'à ce que le thread se soit arrêté (et devrait retourner immédiatement si le thread est déjà mort). Vous pouvez donc vous joindre à tous vos fils en séquence, puis quitter. Si toutes vos jointures sont revenues, tous les threads sont sortis.

De nombreuses bibliothèques de threads vous permettent d'ajouter un délai d'attente à la jointure, ce que vous voudrez probablement faire. De cette façon, même si l'un de vos threads se bloque, votre code de sortie ne bloque pas.

+0

Note mineure. Avant d'appeler Join, vous devez ajouter l'appel à RequestAdditionalTime sinon le SCM vous fermera quand même –

+0

De son code d'exemple, il est clair que sa bibliothèque de threads est l'espace de noms .net 'System.Threading'. – Reinderien

+0

Thread.Join une meilleure approche. Fonctionnellement, c'est la même chose que je fais, mais c'est beaucoup plus propre. Il souffre encore d'être basé sur le temps, mais je peux vivre avec ça. Une idée de comment je peux l'utiliser avec un ThreadPool? Ou dois-je générer des threads? –

Questions connexes