2010-02-22 3 views
8

J'essaye d'écrire un ThreadManager pour mon application C#. Je crée plusieurs threads:
Un fil pour mon écrivain de texte.
Un thread qui surveille certaines statistiques.
Plusieurs threads pour effectuer une grande séquence de calculs (jusqu'à 4 threads par core et je lance mon application sur un serveur quad core 2x).Arrêt d'une application multithread

Mon application s'exécute normalement jusqu'à 24 heures à la fois, de sorte que tous les threads sont créés au début et qu'ils persistent tout le temps que l'application s'exécute.

Je veux avoir un seul endroit où je "enregistre" toutes mes bandes de roulement et quand l'application s'arrête, j'appelle simplement une méthode et elle passe par tous les threads enregistrés et les ferme.

A cette fin, je l'ai mis au point la classe suivante:

public class ThreadManager 
{ 
    private static Object _sync = new Object(); 
    private static ThreadManager _instance = null; 
    private static List<Thread> _threads; 
    private ThreadManager() 
    { 
     _threads = new List<Thread>(); 
    } 

    public static ThreadManager Instance 
    { 
     get 
     { 
      lock (_sync) 
      { 
       if (_instance == null) 
       { 
        _instance = new ThreadManager(); 
       } 
      } 
      return _instance; 
     } 
    } 

    public void AddThread(Thread t) 
    { 
     lock (_sync) 
     { 
      _threads.Add(t); 
     } 
    } 

    public void Shutdown() 
    { 
     lock (_sync) 
     { 
      foreach (Thread t in _threads) 
      { 
       t.Abort(); // does this also abort threads that are currently blocking? 
      } 
     } 
    } 
} 

Je veux faire en sorte que tous mes fils sont tués pour que l'application peut se fermer correctement et arrêter au milieu d'un calcul est très bien aussi. Devrais-je être au courant de quelque chose ici? Cette approche est-elle bonne compte tenu de ma situation?

+0

WOW! Beaucoup de bonnes réponses ... c'est difficile à choisir maintenant. J'ai donné la coche à Nate parce qu'il était le premier, et il serait injuste de l'enlever. Voyons voir ce que les votes disent. Je reçois quelque chose d'utile de toutes vos réponses, alors s'il vous plaît votez vos coeurs. – Kiril

+0

Le comportement par défaut des threads du pool de threads est le même que celui que j'ai suggéré. Si vous ne vous souciez pas que vos threads ne finissent pas, le mien est la solution la plus simple. Évidemment, les autres réponses font de bons points sur la gestion des threads, mais vous indiquez clairement que tuer des threads au milieu d'un calcul est bien. –

+0

Je suis d'accord avec vous Nate;), je ne vais pas enlever la coche, parce qu'il serait injuste et vous m'a donné la réponse la plus précise, rapide et simple ... Je ne veux que d'autres pour obtenir leur juste crédit, donc je veux que tout le monde vote pour toutes les bonnes réponses. – Kiril

Répondre

16

Si vous définissez les threads sur les threads d'arrière-plan, ils seront supprimés lorsque l'application sera arrêtée. De toute évidence, si vous avez besoin des threads pour terminer avant l'arrêt, ce n'est pas la solution que vous voulez.

+0

Merci Nate, je mets tous mes fils à fils de fond quand je les crée ... ce que cela signifie que je ne ai pas besoin de les abandonner à tout? – Kiril

+0

oui, si elles sont définies sur des threads d'arrière-plan, la fermeture de l'application forcera les threads à quitter. http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx –

2

La seule question spécifique que je sais est celui-ci: http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx

Mais il faut éviter d'avoir à recourir à une conception comme celui-ci. Vous pouvez forcer chacun de vos threads à vérifier régulièrement un drapeau qu'il est temps de s'arrêter, et lors de la fermeture, placez ce drapeau et attendez que tous les threads se terminent (avec Join()). Cela ressemble un peu plus à un arrêt contrôlé de cette façon.

14

L'annulation de threads est ce que vous faites lorsque tout le reste échoue. C'est une chose dangereuse à faire que vous ne devriez faire qu'en dernier recours. La façon correcte de faire cela est de rendre votre logique de threading afin que chaque thread de travail réponde rapidement et correctement quand le thread principal lui donne la commande de se fermer.

Par coïncidence, c'est le sujet de mon blog cette semaine.

http://blogs.msdn.com/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx

+1

Ce fil abort exceptions sont bloquées pendant l'exécution des blocs finally est nouveau pour moi. Merci d'ajouter ceci. –

+0

@ fatcat1111: En effet, rien ne garantit qu'un thread avorté s'arrêtera * jamais * suite à l'abandon. Juste une autre raison d'éviter Thread.Abort; c'est à la fois dangereux * et * peu fiable. –

+0

D'accord, définitivement une option de dernier recours. –

3

si AddThread est appelé pendant que votre arrêt est en marche?

Lorsque l'arrêt est terminé, le thread en attente dans AddThread ajoute un nouveau thread à la collection. Cela pourrait entraîner des blocages dans votre application.

Ajoutez un indicateur bool que vous définissez uniquement dans Shutdown pour vous protéger contre cela.

bool shouldGoAway = false; 
public void AddThread(Thread t) 
{ 
    lock (_sync) 
    { 
     if(! shouldGoAway) 
      _threads.Add(t); 
    } 
} 

public void Shutdown() 
{ 
    lock (_sync) 
    { 
     shouldGoAway = true; 
     foreach (Thread t in _threads) 
     { 
      t.Abort(); // does this also abort threads that are currently blocking? 
     } 
    } 

De même, vous ne devriez pas utiliser de membres statiques - il n'y a aucune raison pour cela puisque vous avez votre instance de Singleton.

.Abort() n'annule pas les threads qui bloquent dans l'espace non géré.Donc, si vous faites cela, vous devez utiliser un autre mécanisme.

1

Si vous ne se soucient pas de la boucle état de thread de travail, vous pouvez par _thread et interrompra:

void DieDieDie() 
{ 
    foreach (Thread thread in _thread) 
    { 
     thread.Abort(); 
     thread.Join(); // if you need to wait for the thread to die 
    } 
} 

Dans votre cas, vous pouvez probablement les abandonner tout et l'arrêt comme ils le font tout simplement des calculs . Mais si vous devez attendre une opération d'écriture de base de données ou devez fermer une ressource non gérée, vous devez soit capturer l'exception ThreadAbortException, soit signaler aux threads de se tuer correctement.

0

Vous voulez différée annulation de fil, ce qui signifie essentiellement que les fils se terminent par opposition à un gestionnaire de threads annulation threads de manière asynchrone, ce qui est beaucoup plus mal défini et dangereux.

Je vous voulais gérer l'annulation de fil plus élégante que la résiliation immédiate, vous pouvez utiliser les gestionnaires de signaux qui sont déclenchés par des événements hors du fil - par votre gestionnaire de fil peut-être.

Questions connexes