2009-12-22 9 views
3

Disons que j'ai cette classe Logger qui enregistre des chaînes dans un thread de travail de priorité faible, qui n'est pas un thread d'arrière-plan. Les chaînes sont placées dans la file d'attente au Logger.WriteLine et grignotées au Logger.Worker. Aucune chaîne en file d'attente ne peut être perdue. À peu près comme celui-ci (mise en œuvre, le verrouillage, la synchronisation, etc. omis pour la clarté):Une classe avec un membre Thread doit-elle implémenter IDisposable?

public class Logger 
{ 
    private Thread workerThread; 
    private Queue<String> logTexts; 
    private AutoResetEvent logEvent; 
    private AutoResetEvent stopEvent; 

    // Locks the queue, adds the text to it and sets the log event. 
    public void WriteLine(String text); 

    // Sets the stop event without waiting for the thread to stop. 
    public void AsyncStop(); 

    // Waits for any of the log event or stop event to be signalled. 
    // If log event is set, it locks the queue, grabs the texts and logs them. 
    // If stop event is set, it exits the function and the thread. 
    private void Worker(); 
} 

Depuis le thread de travail est un fil de premier plan, je dois être en mesure d'arrêter de manière déterministe si le processus devrait être en mesure de terminer .

Question: Est-ce la recommandation générale dans ce scénario pour laisser Logger mettre en œuvre IDisposable et arrêter le thread de travail dans Dispose()? Quelque chose comme ceci:

public class Logger : IDisposable 
{ 
    ... 

    public void Dispose() 
    { 
     AsyncStop(); 
     this.workerThread.Join(); 
    } 
} 

Ou y at-il de meilleures façons de le manipuler?

Répondre

3

Ce serait certainement travailler - un Thread qualifie comme une ressource, etc. Le principal avantage de IDisposable provient de la déclaration using, donc cela dépend vraiment de savoir si l'utilisation typique pour le propriétaire de l'objet est d'utiliser la objet pour une durée de temps en une seule méthode -

void Foo() { 
    ... 
    using(var obj = YourObject()) { 
     ... some loop? 
    } 
    ... 
} 

Si cela est logique (peut-être une pompe de travail), alors tout va bien; IDisposable serait utile dans le cas où une exception est levée. Si ce n'est pas l'utilisation typique alors autre que en soulignant qu'il a besoin de une sorte de nettoyage, ce n'est pas tout à fait si utile.

1

C'est généralement le meilleur, tant que vous avez un moyen déterministe de disposer de l'enregistreur (en utilisant un bloc sur la partie principale de l'application, essayez/enfin, gestionnaire d'arrêt, etc).

1

Il peut être judicieux que le thread contienne une référence faible pour l'objet de gestion et vérifie périodiquement qu'il existe toujours. En théorie, vous pourriez utiliser un finaliseur pour pousser votre thread (notez que le finalizer, contrairement à Dispose, ne devrait pas faire de Thread.Join), mais cela peut être une bonne idée d'autoriser la possibilité d'échec du finalizer.

1

Vous devez savoir que si l'utilisateur n'appelle pas Dispose manuellement (via ou autrement), l'application ne se fermera jamais, car l'objet Thread contiendra une référence forte à votre Logger. Réponse fournie par supercat est une meilleure solution générale à ce problème.

Questions connexes