Проходит ли System.Timers.Timer в отдельном потоке, а не в потоке, который его создал?
Допустим, у меня есть класс с таймером, который срабатывает каждые 5 секунд. Когда срабатывает таймер, в прошедшем методе изменяется какой-то объект. Допустим, изменение этого объекта занимает много времени, например 10 секунд. Возможно ли, что я столкнусь с конфликтами потоков в этом сценарии?
c#
multithreading
timer
user113164
источник
источник
Ответы:
Для System.Timers.Timer :
См . Ответ Брайана Гидеона ниже
Для System.Threading.Timer :
В документации MSDN по таймерам говорится:
Так что действительно таймер истекает в другом потоке.
источник
Это зависит.
System.Timers.Timer
Имеет два режима работы.Если
SynchronizingObject
установлен вISynchronizeInvoke
экземпляр,Elapsed
событие будет выполняться в потоке, в котором размещается синхронизирующий объект. Обычно этиISynchronizeInvoke
случаи не что иное , как обычный старыйControl
иForm
экземпляры , что мы все знакомы. В этом случаеElapsed
событие вызывается в потоке пользовательского интерфейса и ведет себя аналогичноSystem.Windows.Forms.Timer
. В противном случае это действительно зависит от конкретногоISynchronizeInvoke
экземпляра, который использовался.Если
SynchronizingObject
имеет значение null, тоElapsed
событие вызывается вThreadPool
потоке и ведет себя аналогичноSystem.Threading.Timer
. Фактически, он фактически используетSystem.Threading.Timer
скрытую информацию и выполняет операцию маршалинга после получения обратного вызова таймера, если это необходимо.источник
System.Threading.Timer
илиSystem.Timers.Timer
?System.Timers.Timer
есть два режима работы. Он может работать в случайно назначенном потоке пула потоков ИЛИ в любом потоке, в котором размещенISynchronizeInvoke
экземпляр. Я не знаю, как прояснить это.System.Threading.Timer
имеет мало общего (если вообще есть) с исходным вопросом.lock
для этого?Каждое прошедшее событие будет запускаться в том же потоке, если предыдущее Elapsed еще не запущено.
Так что он обрабатывает столкновение за вас
попробуйте поместить это в консоль
вы получите что-то вроде этого
где 10 - вызывающий поток, а 6 и 12 запускаются из истекшего события bg. Если удалить Thread.Sleep (2000); вы получите что-то вроде этого
Поскольку коллизий нет.
Но это по-прежнему оставляет вам проблему. если вы запускаете событие каждые 5 секунд, а редактирование занимает 10 секунд, вам нужна блокировка, чтобы пропустить некоторые изменения.
источник
timer.Stop()
в начало метода события Elapsed, а затемtimer.Start()
в конец метода события Elapsed предотвратит столкновение события Elapsed.Для System.Timers.Timer в отдельном потоке, если SynchronizingObject не установлен.
Вы увидите, сработал ли DummyTimer с интервалом в 5 секунд:
Итак, как видно, OnDummyTimerFired выполняется в потоке Workers.
Нет, дальнейшее усложнение - если вы уменьшите интервал до 10 мс,
Это связано с тем, что если предыдущее выполнение OnDummyTimerFired не было выполнено при следующем запуске тика, .NET создаст новый поток для выполнения этой работы.
Еще больше усложняя ситуацию: «Класс System.Timers.Timer обеспечивает простой способ решения этой дилеммы - он предоставляет общедоступное свойство SynchronizingObject. Установка этого свойства в экземпляр Windows Form (или элемент управления в Windows Form) гарантирует что код в вашем обработчике событий Elapsed выполняется в том же потоке, в котором был создан экземпляр SynchronizingObject ".
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2
источник
Если прошедшее событие занимает больше времени, чем интервал, он создаст еще один поток, чтобы вызвать истекшее событие. Но для этого есть обходной путь
источник