Czy System.Timers.Timer upływa w osobnym wątku niż wątek, który go utworzył?
Powiedzmy, że mam zajęcia ze stoperem, który uruchamia się co 5 sekund. Po uruchomieniu licznika czasu w metodzie elapsed jakiś obiekt jest modyfikowany. Powiedzmy, że modyfikacja tego obiektu zajmuje dużo czasu, np. 10 sekund. Czy to możliwe, że w tym scenariuszu napotkam kolizje wątków?
c#
multithreading
timer
user113164
źródło
źródło
Odpowiedzi:
Dla System.Timers.Timer :
Zobacz odpowiedź Briana Gideona poniżej
Dla System.Threading.Timer :
Dokumentacja MSDN dotycząca timerów stwierdza:
Więc rzeczywiście licznik czasu upływa w innym wątku.
źródło
To zależy.
System.Timers.Timer
Posiada dwa tryby pracy.Jeśli
SynchronizingObject
jest ustawiona naISynchronizeInvoke
instancję,Elapsed
zdarzenie zostanie wykonane w wątku obsługującym obiekt synchronizujący. Zwykle teISynchronizeInvoke
przypadki to nic innego jak zwykłe stareControl
iForm
przypadki, które wszyscy znamy. W takim przypadkuElapsed
zdarzenie jest wywoływane w wątku interfejsu użytkownika i zachowuje się podobnie doSystem.Windows.Forms.Timer
. W przeciwnym razie tak naprawdę zależy to od konkretnegoISynchronizeInvoke
wystąpienia, które zostało użyte.Jeśli
SynchronizingObject
jest null, toElapsed
zdarzenie jest wywoływane wThreadPool
wątku i zachowuje się podobnie doSystem.Threading.Timer
. W rzeczywistości faktycznie używaSystem.Threading.Timer
za kulisami i wykonuje operację kierowania po odebraniu wywołania zwrotnego timera, jeśli to konieczne.źródło
System.Threading.Timer
lubSystem.Timers.Timer
?System.Timers.Timer
ma dwa tryby działania. Może działać w losowo przypisanym wątku puli wątków LUB może działać w dowolnym wątku, w którym znajduje sięISynchronizeInvoke
instancja. Nie wiem, jak to wyjaśnić.System.Threading.Timer
ma niewiele (jeśli cokolwiek) wspólnego z pierwotnym pytaniem.lock
?Każde zdarzenie Elapsed zostanie uruchomione w tym samym wątku, chyba że poprzednie Elapsed nadal działa.
Więc obsługuje kolizję za Ciebie
spróbuj umieścić to w konsoli
dostaniesz coś takiego
gdzie 10 jest wątkiem wywołującym, a 6 i 12 odpalają ze zdarzenia minęło bg. Jeśli usuniesz Thread.Sleep (2000); dostaniesz coś takiego
Ponieważ nie ma kolizji.
Ale to wciąż pozostawia problem. jeśli uruchamiasz zdarzenie co 5 sekund, a edycja zajmuje 10 sekund, potrzebujesz trochę blokady, aby pominąć niektóre edycje.
źródło
timer.Stop()
na początku metody zdarzenia Elapsed, a następnietimer.Start()
na końcu metody zdarzenia Elapsed, zapobiegnie kolizji zdarzenia Elapsed.Dla System.Timers.Timer w oddzielnym wątku, jeśli SynchronizingObject nie jest ustawiony.
Na wyjściu zobaczysz, czy DummyTimer uruchomił się co 5 sekund:
Tak więc, jak widać, OnDummyTimerFired jest wykonywany w wątku Workers.
Nie, dalsze komplikacje - jeśli zmniejszysz interwał do 10 ms,
Dzieje się tak, ponieważ jeśli poprzednie wykonanie OnDummyTimerFired nie zostanie wykonane po uruchomieniu następnego ticka, platforma .NET utworzy nowy wątek do wykonania tego zadania.
Co jeszcze bardziej komplikuje sprawę , „Klasa System.Timers.Timer zapewnia łatwy sposób rozwiązania tego dylematu - ujawnia publiczną właściwość SynchronizingObject. Ustawienie tej właściwości na wystąpienie formularza systemu Windows (lub kontrolkę w formularzu systemu Windows) zapewni że kod w programie obsługi zdarzeń Elapsed działa w tym samym wątku, w którym utworzono wystąpienie obiektu SynchronizingObject. "
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2
źródło
Jeśli zdarzenie elapsed trwa dłużej niż interwał, utworzy kolejny wątek, aby zgłosić zdarzenie elapsed. Ale istnieje obejście tego problemu
źródło