Un System.Timers.Timer s'écoule-t-il sur un thread distinct de celui qui l'a créé?
Disons que j'ai une classe avec une minuterie qui se déclenche toutes les 5 secondes. Lorsque la minuterie se déclenche, dans la méthode écoulée, un objet est modifié. Disons que cela prend beaucoup de temps pour modifier cet objet, comme 10 secondes. Est-il possible que je rencontre des collisions de threads dans ce scénario?
c#
multithreading
timer
user113164
la source
la source
Réponses:
Pour System.Timers.Timer :
Voir la réponse de Brian Gideon ci-dessous
Pour System.Threading.Timer :
La documentation MSDN sur les minuteries indique:
Donc, en effet, la minuterie s'écoule sur un fil différent.
la source
Ça dépend. Le
System.Timers.Timer
a deux modes de fonctionnement.Si
SynchronizingObject
est défini sur uneISynchronizeInvoke
instance, l'Elapsed
événement s'exécutera sur le thread hébergeant l'objet de synchronisation. Habituellement, cesISynchronizeInvoke
instances ne sont rien d'autre que des instances anciennesControl
et desForm
instances que nous connaissons tous. Donc, dans ce cas, l'Elapsed
événement est appelé sur le thread d'interface utilisateur et il se comporte de la même manière que leSystem.Windows.Forms.Timer
. Sinon, cela dépend vraiment de l'ISynchronizeInvoke
instance spécifique qui a été utilisée.Si
SynchronizingObject
est null, l'Elapsed
événement est appelé sur unThreadPool
thread et se comporte de la même manière que leSystem.Threading.Timer
. En fait, il utilise en fait unSystem.Threading.Timer
dans les coulisses et effectue l'opération de marshaling après avoir reçu le rappel du minuteur si nécessaire.la source
System.Threading.Timer
ouSystem.Timers.Timer
?System.Timers.Timer
a deux modes de fonctionnement. Il peut s'exécuter sur un thread de pool de threads attribué au hasard OU il peut s'exécuter sur n'importe quel thread hébergeant l'ISynchronizeInvoke
instance. Je ne sais pas comment rendre cela plus clair.System.Threading.Timer
a peu (voire rien) à voir avec la question initiale.lock
pour ça?Chaque événement écoulé se déclenchera dans le même thread à moins qu'un précédent Elapsed ne soit toujours en cours d'exécution.
Donc, il gère la collision pour vous
essayez de mettre ça dans une console
vous obtiendrez quelque chose comme ça
où 10 est le thread appelant et 6 et 12 sont déclenchés à partir de l'événement bg elapsed. Si vous supprimez le Thread.Sleep (2000); vous obtiendrez quelque chose comme ça
Puisqu'il n'y a pas de collisions.
Mais cela vous laisse toujours un problème. si vous déclenchez l'événement toutes les 5 secondes et qu'il faut 10 secondes pour le modifier, vous avez besoin d'un verrouillage pour ignorer certaines modifications.
la source
timer.Stop()
au début de la méthode d'événement Elapsed, puis d'untimer.Start()
à la fin de la méthode d'événement Elapsed empêchera l'événement Elapsed de se heurter.Pour System.Timers.Timer, sur un thread distinct, si SynchronizingObject n'est pas défini.
Sortie vous verriez si DummyTimer s'est déclenché à 5 secondes d'intervalle:
Ainsi, comme on le voit, OnDummyTimerFired est exécuté sur le thread Workers.
Non, complication supplémentaire - Si vous réduisez l'intervalle à 10 ms,
En effet, si l'exécution précédente d'OnDummyTimerFired n'est pas effectuée lors du déclenchement suivant, .NET créerait un nouveau thread pour effectuer ce travail.
Pour compliquer encore les choses, "La classe System.Timers.Timer fournit un moyen simple de résoudre ce dilemme: elle expose une propriété SynchronizingObject publique. La définition de cette propriété sur une instance d'un Windows Form (ou un contrôle sur un Windows Form) garantira que le code de votre gestionnaire d'événements Elapsed s'exécute sur le même thread sur lequel le SynchronizingObject a été instancié. "
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2
la source
Si l'événement écoulé prend plus de temps que l'intervalle, il créera un autre thread pour déclencher l'événement écoulé. Mais il existe une solution de contournement pour cela
la source