Comment comptez-vous fermer une application lorsque certains WaitHandle est au milieu d'un appel à WaitOne?

StackOverflow https://stackoverflow.com/questions/3087683

Question

Y at-il un moyen standard pour fermer une application « proprement », tandis que certains objets WaitHandle peuvent être dans l'état d'un appel de blocage de courant à WaitOne?

Par exemple, il peut y avoir un fil de fond qui tourne le long d'une méthode de ce type:

while (_request.WaitOne())
{
    try
    {
        _workItem.Invoke();
    }
    finally
    {
        OnWorkCompleted();
    }
}

Je ne vois pas de façon évidente de disposer de ce fil sans appeler Thread.Abort (qui d'après ce que je comprends est découragé). Appel Close sur l'objet _request (un AutoResetEvent), cependant, lancera une exception.

À l'heure actuelle, le fil qui exécute cette boucle a sa propriété IsBackground ensemble à true, et donc l'application apparaît pour fermer correctement. Cependant, étant donné que WaitHandle outils IDisposable, je ne suis pas sûr si cela est considéré comme casher ou si cet objet doit vraiment être mis au rebut avant la sortie de l'application.

Est-ce une mauvaise conception? Sinon, comment est-ce scénario généralement traité?

Était-ce utile?

La solution

Définir un WaitHandle supplémentaire appelé _terminate qui signalera une demande de mettre fin à la boucle, puis utiliser WaitHandle.WaitAny au lieu de WaitHandle.WaitOne.

var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
  try
  {
    _workItem.Invoke();
  }
  finally
  {
    OnCompleteWork();
  }
}

Autres conseils

Quand un thread bloque (indépendamment de ce qu'il bloque sur), vous pouvez appeler Thread.Interrupt() Cela entraînera la ThreadInterruptedException d'exception (je crois, il est peut-être un peu différent) Vous pouvez gérer cette exception sur le fil lui-même et faire tout neccesary nettoyer.

Il convient de noter que le fil ne jeter le ThreadInterruptedException quand il bloque, si elle ne le bloque ne sera pas jeté jusqu'à ce qu'il tente de bloquer suivant.

Ceci est la voie « sûr » de mettre fin à des fils de ce que j'ai lu sur le sujet.

on peut également noter: si l'objet implémente IDisposable et un finializer (ce qui sera si elle utilise des ressources non gérés) du GC appelleront le finaliseur qui appelle normalement disposer. Normalement, c'est non déterministe. Cependant, vous pouvez très bien garantir qu'ils sera appelé à la sortie de l'application. Seulement dans des circonstances très particulières qu'ils ne le feraient pas. (A .net environnement exception de termininating comme StackOverflowException est jeté)

Définissez la propriété IsBackground à true ... il doit se fermer automatiquement le fil lorsque la fin de votre application.

Vous pouvez également interrompre le fil en appelant Thread.Interrupt et gérer les ThreadInterruptedException . Une autre idée est d'appeler _request.Set() et faire le pour déterminer si la demande est ferme ou si elle doit continuer while vérifier un drapeau volatile:

private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
    //...
}

// somewhere else in the app
_running = false;
_request.Set();

Je pense que le système d'exploitation va nettoyer après votre processus terminé. Parce que votre fil est marqué comme IsBackground le CLR fin du processus et tous les fils à l'intérieur, donc ce n'est pas un problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top