87 votes

C# Minuteries s'écouler sur un thread séparé?

Ne un Système.Les minuteries.La minuterie s'écouler sur un autre thread que le thread qui l'a créé?

Disons que j'ai une classe avec un timer qui déclenche toutes les 5 secondes. Lorsque le compte à rebours incendies, dans l'écoulement de la méthode, un objet est modifié. Permet de dire qu'il faut du temps pour modifier cet objet, à l'instar de 10 secondes. Est-il possible que je vais courir dans le thread des collisions dans ce scénario?

183voto

Brian Gideon Points 26683

Il dépend. L' System.Timers.Timer a deux modes de fonctionnement.

Si SynchronizingObject est définie à une ISynchronizeInvoke instance puis l' Elapsed événement s'exécuter sur le fil d'hébergement de la synchronisation de l'objet. Habituellement, ces ISynchronizeInvoke des occurrences sont rien d'autre que le bon vieux Control et Form des occurrences que nous sommes tous familiers avec. Donc, dans ce cas, l' Elapsed événement est appelée sur le thread d'INTERFACE utilisateur et il se comporte de façon similaire à l' System.Windows.Forms.Timer. Sinon, cela dépend vraiment de la spécifique, ISynchronizeInvoke de l'instance qui a été utilisé.

Si SynchronizingObject est vide alors l' Elapsed événement est invoquée sur un ThreadPool fil et il se comporte de façon similaire à l' System.Threading.Timer. En fait, il utilise en fait un System.Threading.Timer derrière les coulisses et le regroupement de l'opération après , il reçoit la minuterie de rappel si nécessaire.

57voto

Joren Points 7911

La Documentation MSDN sur des Minuteries états:

Le Système.Le filetage.Classe Timer fait rappels sur un pool de threads threadet ne pas utiliser le modèle d'événement.

Donc en effet la minuterie s'écoule sur un thread différent.

21voto

Simon Points 11945

Chaque événement écoulée aura le feu dans le même thread, à moins d'une précédente Écoulé est toujours en cours d'exécution.

Donc, 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 ceci

10
6
12
6
12

où 10 est le thread appelant et 6 et 12 sont à tirer de la bg événement écoulée. Si vous retirez le Fil.Sleep(2000); vous obtiendrez quelque chose comme ceci

10
6
6
6
6

Depuis il n'y a pas de collisions.

Mais cela laisse tout de même de u avec un problème. si u sont à tirer de l'événement, toutes les 5 secondes et ça prend 10 secondes pour modifier u besoin de quelques verrouillage de passer outre certaines modifications.

15voto

Swab.Jat Points 209

Pour Le Système.Les minuteries.À rebours, sur le thread, si SynchronizingObject n'est pas définie.

    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 que vous verriez si DummyTimer tiré à 5 secondes d'intervalle:

Main Thread Id: 9
   12
   12
   12
   12
   12
   ... 

Donc, comme on le voit, OnDummyTimerFired est exécutée sur les Travailleurs fil.

Non, complication supplémentaire - Si vous réduisez l'intervalle de 10 ms,

Main Thread Id: 9
   11
   13
   12
   22
   17
   ... 

C'est parce que si prev exécution de OnDummyTimerFired n'est pas fait lors de la prochaine tique est tiré, puis .NET serait de créer un nouveau thread pour faire ce travail.

Compliquant encore plus les choses, "Le Système de.Les minuteries.Classe Timer fournit un moyen facile de traiter ce dilemme, il expose un public SynchronizingObject de la propriété. La définition de cette propriété à une instance d'un Formulaire Windows (ou d'un contrôle sur un Formulaire Windows) permettra de s'assurer que le code dans votre Écoulé gestionnaire d'événement s'exécute sur le même thread sur lequel le SynchronizingObject a été instancié."

(On aime compliquer les choses n'est-ce pas? Tout ce qui est nécessaire est un god damn timer - la Première Règle lorsque vous enseignez les Modèles de Conception devraient être la "Simplicité")

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2

12voto

Rajan Points 51

Si l'événement écoulé prend plus de temps, alors l'intervalle, il va créer un autre thread pour déclencher l'événement écoulée. Mais il existe une solution de contournement pour ce

static void timer_Elapsed(object sender, ElapsedEventArgs e)    
{     
   try
   {
      timer.Stop(); 
      Thread.Sleep(2000);        
      Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);    
   }
   finally
   {
     timer.Start();
   }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X