I timer C # vengono trascorsi su un thread separato?

Un System.Timers.Timer trascorre su un thread separato rispetto al thread che lo ha creato?

Diciamo che ho una lezione con un timer che scatta ogni 5 secondi. Quando il timer scocca, nel metodo trascorso, alcuni oggetti vengono modificati. Diciamo che ci vuole molto tempo per modificare questo object, come 10 secondi. È ansible che mi imbatterò in collisioni di thread in questo scenario?

Per System.Timers.Timer :

Vedi sotto la risposta di Brian Gideon

Per System.Threading.Timer :

La documentazione MSDN sui timer indica:

La class System.Threading.Timer effettua callback su un thread ThreadPool e non utilizza affatto il modello di eventi.

Quindi, in effetti, il timer trascorre su un thread diverso.

Dipende. System.Timers.Timer ha due modalità di funzionamento.

Se SynchronizingObject è impostato su un’istanza ISynchronizeInvoke l’evento Elapsed verrà eseguito sul thread che ospita l’object di sincronizzazione. Di solito queste istanze di ISynchronizeInvoke non sono nient’altro che semplici vecchie istanze di Control e Form che tutti conosciamo. In tal caso, l’evento Elapsed viene richiamato sul thread dell’interfaccia utente e si comporta in modo simile a System.Windows.Forms.Timer . In caso contrario, dipende in realtà ISynchronizeInvoke specifica che è stata utilizzata.

Se SynchronizingObject è null, l’evento Elapsed viene richiamato su un thread ThreadPool e si comporta in modo simile a System.Threading.Timer . Infatti, in realtà utilizza un System.Threading.Timer dietro le quinte e esegue l’operazione di marshalling dopo aver ricevuto la richiamata del timer, se necessario.

Ogni evento trascorso si attiverà nello stesso thread, a meno che non sia ancora in esecuzione un precedente trascorso.

Quindi gestisce la collisione per te

prova a metterlo in una 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); } 

otterrai qualcosa di simile

 10 6 12 6 12 

dove 10 è il thread chiamante e 6 e 12 stanno sparando dall’evento trascorso bg. Se si rimuove il Thread.Sleep (2000); otterrai qualcosa di simile

 10 6 6 6 6 

Dal momento che non ci sono collisioni.

Ma questo ti lascia ancora un problema. se stai sparando l’evento ogni 5 secondi e ci vogliono 10 secondi per modificarlo hai bisogno di un po ‘di blocco per saltare alcune modifiche.

Per System.Timers.Timer, su thread separato, se SynchronizingObject non è impostato.

  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; } 

Output che vedresti se DummyTimer ha triggersto l’intervallo di 5 secondi:

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

Quindi, come visto, OnDummyTimerFired viene eseguito sul thread Workers.

No, ulteriore complicazione: se riduci l’intervallo per dire 10 ms,

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

Questo perché se l’esecuzione precedente di OnDummyTimerFired non viene eseguita quando viene triggersto il segno di spunta successivo, .NET creerà un nuovo thread per eseguire questo lavoro.

Complicando ulteriormente le cose, “La class System.Timers.Timer fornisce un modo semplice per affrontare questo dilemma: espone una proprietà pubblica SynchronizingObject. L’impostazione di questa proprietà su un’istanza di un Windows Form (o un controllo su un Windows Form) assicurerà che il codice nel gestore eventi Elapsed viene eseguito sullo stesso thread su cui è stato creato l’istanza di SynchronizingObject. “

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

Se l’evento trascorso richiede più tempo dell’intervallo, verrà creato un altro thread per aumentare l’evento trascorso. Ma c’è una soluzione per questo

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