Disposer correctement de la classe thread
J'ai une assez complexe multi-thread service Windows de travail, mais je ne peux pas comprendre comment le nettoyer correctement. Ci-dessous est une [pseudo] code de montrer ce que j'ai. Le code est beaucoup plus complexe, sans doute trop de copier/coller ici.
En gros, j'ai une Demande de classe qui crée un thread pour faire le travail. Lorsqu'une nouvelle demande arrive dans le port d'écoute, il l'envoie au Processeur, ce qui crée la Demande et maintient la liste des demandes. Si le service est arrêté, je le nettoyage de toutes les demandes dans la liste. Mais lorsque la Demande de travail qui est fait, comment dois-je nettoyer qu'une instance de la classe?
Merci pour toute aide!
Nelson
class Service
{
Listener listener;
Processor processor;
OnStart()
{
processor = new Processor();
listener = new Listener(processor);
}
OnStop()
{
listener.Dispose();
processor.Dispose();
}
}
class Listener
{
Thread thread;
bool terminate = false;
Listener(Processor processor)
{
thread = new Thread(DoWork);
thread.Start(processor);
}
DoWork(Processor processor)
{
WaitForConnection(NewConnection);
}
NewConnection(String data)
{
processor.NewRequest(data);
if (terminate)
return;
WaitForConnection(NewConnection);
}
Dispose()
{
terminate = true;
thread.Join();
}
}
class Processor
{
//I need to maintain this list so that when the service stops I can cleanly close down
List<Request> requests = new List<Request>();
NewRequest(string data)
{
request.Add(new Request(data));
}
Dispose()
{
//Cleanup each request
foreach (Request request in requests)
{
request.Dispose();
}
}
}
class Request
{
Thread thread;
bool terminate;
Request(string data)
{
while (true)
{
//Do some work
Thread.Sleep(1000);
if (doneWorking)
break;
if (terminate)
return;
}
//We're done. If I return this thread stops. But how do I properly remove this Request instance from the Processor.requests list?
}
Dispose()
{
terminate = true;
thread.Join();
}
}
OriginalL'auteur Nelson Rothermel | 2009-09-22
Vous devez vous connecter pour publier un commentaire.
C'est un croquis:
Plus sûr et plus performant... le Verrouillage n'est pas possible depuis l'autre thread sera le supprimer de ma liste, si je verrouiller la liste de la Jointure() ne sera jamais complète. C'est une bonne pratique de ne jamais appel d'une fonction lors d'un verrou est détenu. Aussi, je ne peux pas tout simplement ignorer le verrouillage de la collection sera modifié et ma boucle foreach obtenez une exception.
J'ai eu une expérience de première main sur ce sur une autre partie du code. J'ai pensé que c'était à cause d'un lock() de blocage, mais grâce à vous j'ai pu facilement résoudre.
Ne pas le
terminated
pavillon être déclaré commevolatile
?B. Oui, le volatile modificateur sur résiliée peut améliorer le code ci-dessus; toutefois, pour être complètement honnête, je n'aurais pas la structure du code de cette façon pour commencer.
OriginalL'auteur csharptest.net
Une possibilité est de passer un rappel à la demande sous la forme d'un délégué: "lorsque vous avez terminé le traitement, de me rappeler pour me dire". Ensuite, exécutez simplement le rappel à la fin du traitement de la requête et de le laisser gérer le nettoyage.
Une chose à surveiller: si vous essayez de passer à travers votre liste de disposer des choses et puis essayez de supprimer un élément de la liste dans un autre fil, vous aurez des problèmes. Vous devez probablement tenir un drapeau (consulté le dans un "thread-safe") et une fois que vous avez commencé à l'élimination de tout dans la liste, ignorer les rappels que vous obtenez.
Sur le thread de sécurité, ne serait pas tout simplement verrouiller() résoudre le problème? Si j'essaie de supprimer un élément de la liste et d'en Disposer() me battre pour elle, le foreach ne trouverez pas tous les éléments. Inversement, l'article serait supprimé puis Jetez-le() nettoyer le reste. Je vais vous donner tous les essayer et de vous en informer. Merci encore.
Vous auriez besoin de verrouiller autour de l'ensemble de votre
foreach
boucle qui ne serait pas beaucoup d'utilisation, vraiment, que vous n'avez pas de soins de plus par le temps, c'est fini. Vous pouvez décider exactement comment spécifiques le délégué faudrait - il pourrait être spécifique à chaque demande individuelle, par exemple. Les méthodes anonymes ou les expressions lambda sont susceptibles d'être utiles ici.Pour supprimer un élément, j'étais en boucle et la vérification de ReferenceEquals(), mais ensuite j'ai réalisé que je pouvais juste faire la liste.Supprimer(Demande). Ensuite, si je ne le GC.Collect(), ne devrait pas Disposer() est appelée automatiquement? Dispose() et le destructeur ne sont pas appelés...
Dispose() n'est pas appelé par le GC - seulement le finaliseur est - et vous n'avez pas montré un finaliseur. Cependant, j'ai ne pas suggèrent d'utiliser des outils de finalisation. Juste pour vérifier: - tu définitivement de disposer de la demande? Quel est le rapport qui doit libérer?
OriginalL'auteur Jon Skeet