Résumé: Dans une application Windows Service & Console, j'appelle une bibliothèque commune contenant une minuterie qui déclenche périodiquement une action qui prend environ 30 secondes à compléter. Cela fonctionne bien, cependant ...
Lorsqu'une sortie d'arrêt de service ou d'application est appelée et la minuterie est dans ELAPSEDEventHandler, j'ai besoin de la sortie de service / application de service pour attendre que le gestionnaire d'événements soit terminé. P>
J'ai mis en œuvre cette fonctionnalité en ayant une propriété booléenne inéussion vérifiée lorsque la méthode d'arrêt de la minuterie est appelée. P>
Bien que cela soit fonctionnel, la question est la suivante: est-ce la meilleure façon de faire cela? Existe-t-il une approche alternative qui pourrait mieux servir à cet effet? P>
L'autre problème est que je dois éviter que la demande d'arrêt de service échoue avec un "service n'a pas répondu à la demande d'arrêt" P>
Ceci est ma mise en œuvre p> et c'est comment il est appelé dans l'application Service OnStart / Console Main: P> TimedProcess.Instance.Stop();
3 Réponses :
Modifier P>
Chaque rappel au Vous n'avez pas décrit suffisamment de détails pour savoir si votre application particulière pourrait gérer cette condition de course, il est donc difficile de dire. Mais compte tenu de votre code, il est possible qu'il y ait un rappel en file d'attente pour pour le délai d'attente de service - P>
Un moyen de faire cela consiste à apporter un appel à la méthode code> Méthode code> waitforstatus code> avec un délai d'attente. J'ai fait cela dans le passé et cela fonctionne assez bien, même si je me souviens d'avoir des cas de bord qui attendent très longtemps. P>
Voir le Référence MSDN . Un exemple d'utilisation est décrit ici . P> system.timers.timer code> est mis en file d'attente sur le
threadpool code>. Sachez que le
system.timers.timer code> peut em> avoir une condition de course (vous pouvez en savoir plus sur celui-ci ici .)
system.threading.Timer code> est un emballage légèrement plus agréable que je préfère Utilisez à cause de sa simplicité. p>
processtimer_elapsed code> après
stop () code> est appelé. P>
Toutes mes excuses, je n'ai pas mentionné que la fonctionnalité chronométrée est également appelée à partir d'une demande de console. J'ai édité la question initiale.
Vous l'avez à l'envers. System.Timers.Timer Code> enveloppe le système
System.threading.Timer code> comme objet de minuterie sous-jacent. Il ajoute simplement certaines fonctionnalités au-dessus du système
System.threading.Timer code>. Le
system.timers.timer code> ajoute un objet de synchronisation à utiliser par les consommateurs.
Une alternative possible semble être de ne pas faire le travail réel dans le rappel de la minuterie elle-même mais pour simplement faire une file d'attente d'un élément de travail à partir de la piscine de la bande de roulement pour faire le travail. Ensuite, vous pouvez aller de l'avant et disposer de la minuterie - tout ce qui est en cours d'exécution sur la piscine de thread restera opérationnel et que votre service peut réagir à la demande d'arrêt immédiatement, mais l'élément de pool de threads (si la mise en attente) sera toujours traité. P>
Probablement le moyen le plus simple et le plus fiable consiste à utiliser un Votre programme principal tente de verrouiller cela avant de fermer: P> moniteur code>. Créez un objet que le programme principal et le rappel de la minuterie peuvent accéder à:
bool gotLock = Monitor.TryEnter(_timerLock, TimeSpan.FromSeconds(15));
Jim Jetez un coup d'œil à ceci (3ème note) de Microsoft: MSDN .microsoft.com / fr-US / US / Bibliothèque / System.threading.Timer.aspx À propos des avantages de l'utilisation System.threading.Timer aussi pour les applications de serveur. Vous pouvez obtenir des exceptions aussi lorsque vous terminez.
Comment puis-je utiliser une boîte de dialogue sur le thread principal indiquant l'utilisateur que ce «processus d'arrière-plan» est en cours et lorsque le thread principal est capable de fermer le projet / application, la boîte de dialogue disparaît?
@JakeMith: Vous devriez poster cela comme une nouvelle question.