Question

VB.NET 2010, .NET 4

Bonjour à tous,

J'ai un objet System.Timers.Timer qui fait un travail sur son événement écoulé:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    '...work...
    MasterTimer.Enabled = True
End Sub

Mon problème est que le travail qu'il fait parfois se coincer. Une partie du travail est la communication série il pourrait obtenir attente coincé pour une réponse de quelque chose. Je l'ai déjà modifié mon code de communication en série un peu pour résoudre le problème, espérons. Cependant, cette minuterie est essentiellement le rythme cardiaque d'une application de contrôle de la production et il est très mauvais si elle devait arrêter pour une raison quelconque. Je pensais que ce serait bien de mettre dans un fail-safe délai afin que, si le « travail » prend trop de temps, la minuterie pourrait réactiver lui-même et essayer à nouveau. Je pensais à quelque chose comme ceci:

Déplacer le travail dans un sous-programme et créer un délégué:

Private Delegate Sub WorkDelegate()
Private Sub Work()
   '...work...
End Sub

Appelez le travail en invoquant le délégué puis utilisez WaitOne (délai d'attente) sur le IAsyncResult pour spécifier un délai d'attente:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    Dim workDel as New WorkDelegate(AddressOf Work)
    Dim result as IAsyncResult = workDel.BeginInvoke
    result.AsyncWaitHandle.WaitOne(CInt(MasterTimer.Interval))
    MasterTimer.Enabled = True
End Sub

Mais, ma question est: Est-ce cette cause un problème si le travail () était vraiment coincé quelque part? En ce sens qu'il rentrerait un sous-programme qui est en cours d'exécution? Y at-il un moyen d'interruption de travail () si elle n'a pas fini après le délai d'attente? En d'autres termes, cesser tout l'exécution des travaux () si result.IsCompleted est faux après WaitOne?

Je ne comprends pas vraiment ce genre de choses très bien ainsi, les commentaires seraient grandement appréciés. Peut-être il y a une manière tout à fait différente d'aborder ce que je ne sais pas?

Merci beaucoup à l'avance!

Je voudrais ajouter quelque chose:

Bien que je compte faire quelques réécritures selon les suggestions de Hans, je l'avais déjà prévu une journée d'essais pour tenter d'isoler la source de cette erreur. Jusqu'à présent, il n'a eu lieu lors de l'exécution de l'application compilée. J'ai passé aujourd'hui (et quelques-uns hier) en essayant de reproduire le gel lors de l'exécution en mode débogage afin que peut-être je pourrais ajouter quelques points d'arrêt et comprendre ce qui se passe. Jusqu'à présent, le programme n'a pas gelé en mode débogage. Je me demande s'il y a quelque chose de différent de l'environnement de débogage qui pourrait expliquer cela. Il pourrait juste être que je être « chanceux », mais je l'ai probablement l'exécuter trois fois la longueur moyenne du temps, après quoi le glaça programme lors de l'exécution de l'exécutable ... Encore une fois, je suis assez ignorant, mais il n'y a rien unique au sujet de l'environnement de débogage qui pourrait expliquer cela? Je mettrai à jour à nouveau si elle se fige.

Était-ce utile?

La solution

Cela va mal sur la première ligne du code. La classe System.Timers.Timer est assez dégueu, il n'y a absolument aucune garantie que l'appel Stop () empêchera un autre appel. La minuterie ThreadPool.QueueUserWorkItem utilise pour effectuer l'appel de gestionnaire d'événements échues. Si le threadpool est occupé cela peut finir par faire la queue plusieurs appels, en attendant d'obtenir le feu vert du planificateur de TP pour commencer à courir. L'arrêt de la minuterie n'empêche pas les threads en attente de courir. Sans l'aide d'un verrou, ces fils intensifieront les uns des autres mal et gâcher votre état de communication.

Un SÛR est System.Threading.Timer avec une période de zéro, de sorte que vous obtenez seulement un rappel. Rechargez la minuterie avec la méthode du changement ().

Appel d'une méthode BeginInvoke () d'un délégué puis en bloquant sur elle ne remplissant pas de sens. Il suffit d'appeler Invoke (). vous évite de brûler un autre thread.

Oui, si la méthode « travail » ne revient jamais, alors vous avez un problème. Une une insoluble.

Beaucoup de cette misère pourrait disparaître si vous éviter d'utiliser l'interrogation pour voir s'il y a quelque chose sur le port série. Laissez-vous dire qu'il ya quelque chose d'utile passe. Il déclenche l'événement DataReceived, sur un fil de threadpool, chaque fois qu'il y a au moins un octet dans le tampon de réception. En utilisant sa propriété WriteTimeout est également un excellent moyen d'éviter de se retrouver quand quelque chose ne va pas avec le protocole de communication ou de l'appareil. Consacrer un fil et faire bloquante appels fonctionne bien aussi.

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