Un System.Timers.Timer s'exécute-t-il sur un thread distinct du thread 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, certains objets sont modifiés. Disons qu'il faut beaucoup de temps pour modifier cet objet, comme 10 secondes. Est-il possible que je vais rencontrer des collisions de thread dans ce scénario?Les temporisateurs C# se déroulent-ils sur un thread séparé?
Répondre
Pour System.Timers.Timer:
Voir Brian Gideon's answer below
Pour System.Threading.Timer:
MSDN Documentation on Timers états:
La classe System.Threading.Timer fait les rappels sur un thread ThreadPool et n'utilisent pas du tout le modèle d'événement.
Ainsi, le temporisateur s'écoule sur un thread différent.
C'est vrai, mais c'est une classe complètement différente. L'OP a posé des questions sur la classe System.Timers.Timer. –
Oh, vous avez raison. http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx indique "L'événement Elapsed est déclenché sur un thread ThreadPool." Même conclusion à partir de là je suppose. – Joren
Eh bien, oui, mais ce n'est pas si simple. Vois ma réponse. –
Chaque événement écoulé se déclenche dans le même thread à moins qu'un précédent Elapsed ne soit encore en cours d'exécution.
Il gère la collision pour vous
essayer de mettre cela dans une console
static void Main(string[] args)
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
var timer = new Timer(1000);
timer.Elapsed += timer_Elapsed;
timer.Start();
Console.ReadLine();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Thread.Sleep(2000);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
vous obtiendrez quelque chose comme ça
10
6
12
6
12
où 10 est le fil d'appel et 6 et 12 tirent de l'événement écoulé bg. Si vous supprimez le Thread.Sleep (2000); vous obtiendrez quelque chose comme ceci
10
6
6
6
6
Comme il n'y a pas de collisions.
Mais cela vous laisse toujours un problème. Si vous lancez l'événement toutes les 5 secondes et qu'il faut 10 secondes pour éditer, vous avez besoin d'un verrouillage pour ignorer certaines modifications.
L'ajout de 'timer.Stop()' au début de la méthode d'événement Elapsed, puis un 'timer.Start()' à la fin de la méthode d'événement Elapsed empêcheront l'événement Elapsed d'entrer en collision. –
Vous n'avez pas besoin de mettre timer.Stop() vous avez juste besoin de définir timer.AutoReset = false; alors vous faites timer.Start() après avoir traité l'événement. Je pense que c'est une meilleure façon d'éviter les collisions. –
Cela dépend. Le System.Timers.Timer
a deux modes de fonctionnement.
Si SynchronizingObject
est défini sur une instance ISynchronizeInvoke
, l'événement Elapsed
s'exécutera sur le thread hébergeant l'objet de synchronisation. Habituellement, ces instances ISynchronizeInvoke
ne sont rien d'autre que de simples anciennes instances Control
et Form
que nous connaissons tous. Dans ce cas, l'événement Elapsed
est appelé sur le thread d'interface utilisateur et se comporte de la même manière que le System.Windows.Forms.Timer
. Sinon, cela dépend vraiment de l'instance spécifique ISynchronizeInvoke
qui a été utilisée.
Si SynchronizingObject
est nul alors l'événement Elapsed
est invoquée sur un fil ThreadPool
et il se comporte comme l'System.Threading.Timer
.En fait, il utilise en fait un System.Threading.Timer
dans les coulisses et fait l'opération de marshaling après il reçoit le rappel de minuterie si nécessaire.
Bonne réponse, merci pour cela. –
Si vous vouliez que le rappel du temporisateur s'exécute sur un nouveau thread, devriez-vous utiliser un System.Threading.Timer ou un System.Timers.Timer? – CJ7
@ cj7: L'un ou l'autre peut le faire. –
Si l'événement écoulé prend plus de temps que l'intervalle, il crée un autre thread pour augmenter l'événement écoulé. Mais il existe une solution de contournement pour cela
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
timer.Stop();
Thread.Sleep(2000);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
finally
{
timer.Start();
}
}
+1 Réponse simple et nette, mais cela ne fonctionnera pas toujours. Il faut plutôt utiliser la propriété lock ou SynchronizingObject de timer. – RollerCosta
Pour System.Timers.Timer, sur thread distinct, si SynchronizingObject n'est pas défini.
static System.Timers.Timer DummyTimer = null;
static void Main(string[] args)
{
try
{
Console.WriteLine("Main Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
DummyTimer = new System.Timers.Timer(1000 * 5); // 5 sec interval
DummyTimer.Enabled = true;
DummyTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnDummyTimerFired);
DummyTimer.AutoReset = true;
DummyTimer.Start();
Console.WriteLine("Hit any key to exit");
Console.ReadLine();
}
catch (Exception Ex)
{
Console.WriteLine(Ex.Message);
}
return;
}
static void OnDummyTimerFired(object Sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);
return;
}
sortie vous verriez si DummyTimer tiré sur l'intervalle de 5 secondes:
Main Thread Id: 9
12
12
12
12
12
...
Ainsi, comme on le voit, OnDummyTimerFired est exécuté sur fil travailleurs.
Non, complication supplémentaire - Si vous réduisez l'intervalle dire 10 ms,
Main Thread Id: 9
11
13
12
22
17
...
En effet, si l'exécution précédente de OnDummyTimerFired ne se fait pas lors de son prochain tick est tiré, alors .NET créeraient une nouvelle thread pour faire ce travail. Compléter les choses davantage, "La classe System.Timers.Timer fournit un moyen simple de résoudre ce dilemme: elle expose une propriété publique SynchronizingObject. Windows Form) garantira que le code dans votre gestionnaire d'événements Elapsed s'exécute sur le même thread sur lequel le SynchronizingObject a été instancié. "
C'est un bon exemple. Je ne savais pas jusqu'à maintenant et j'ai besoin de mettre des verrous ici et là. Parfait. –
- 1. C#: Préchargement de formulaires sur un thread séparé
- 2. NSURLDécharger des méthodes de délégué sur un thread séparé
- 3. Comment puis-je exécuter certaines commandes sur un thread séparé?
- 4. Les opérations invoquées sur un objet via JMX s'exécutent-elles dans un thread séparé?
- 5. Android: communication HTTP/JSON dans les applications ou thread séparé?
- 6. boost: thread se bloque compilateur C++ microsoft
- 7. Déclenchement d'une méthode pour exécution dans un thread séparé
- 8. Exécution de SimpleXMLRPCServer dans un thread séparé et fermeture
- 9. Quelle est la meilleure approche pour gérer les exceptions lancées dans un thread séparé?
- 10. Exécution d'un processus ou d'un thread séparé dans Qt
- 11. C#: Invoque une méthode avec [type] .InvokeMember() dans un thread séparé
- 12. Modifier NotifyIcon sur un formulaire séparé
- 13. Quitter un blocage de thread sur TCP read in C#
- 14. Que fait select (2) si vous fermez (2) un descripteur de fichier dans un thread séparé?
- 15. en utilisant pyunit sur un thread réseau
- 16. Passage d'un jeton d'emprunt d'identité sur un thread géré à un thread non géré
- 17. Sur Win32, comment déplacez-vous un thread vers un autre core CPU?
- 18. Tableau séparé pour les objets de valeur sur NHibernate
- 19. WritableBitmap ne fonctionne pas sur un thread distinct?
- 20. Extension du code C# avec un assembly séparé
- 21. C# Thread in Thread: comment obtenir SynchronizationContext.Current?
- 22. Vidage du fichier dans un fichier séparé avec tomcat?
- 23. J'ai besoin d'aide pour obtenir des informations sur un thread d'interface utilisateur et un autre thread dans C#
- 24. Silverlight ViewBase dans un assemblage séparé - possible?
- 25. Sous-répertoire Detatch dans un dépôt git séparé - Sur github
- 26. Thread ListBox C# SharpDevelop
- 27. Les exceptions doivent-elles être placées dans un paquet séparé?
- 28. C# effacement du thread principal
- 29. Exécuter une instruction après que le thread se termine
- 30. C++ Laisser un thread d'accélération attendre 1 seconde
Cela pourrait conduire à des problèmes. Notez qu'en général, les threads de pool de threads ne sont pas conçus pour les processus de longue durée. –