Um System.Timers.Timer decorre em um thread separado do thread que o criou?
Digamos que eu tenha uma aula com um cronômetro que dispara a cada 5 segundos. Quando o cronômetro dispara, no método decorrido, algum objeto é modificado. Vamos dizer que leva muito tempo para modificar este objeto, como 10 segundos. É possível que eu tenha colisões de threads neste cenário?
c#
multithreading
timer
user113164
fonte
fonte
Respostas:
Para System.Timers.Timer :
Veja a resposta de Brian Gideon abaixo
Para System.Threading.Timer :
A documentação do MSDN sobre timers afirma:
Então, de fato, o cronômetro passa em um segmento diferente.
fonte
Depende. O
System.Timers.Timer
possui dois modos de operação.Se
SynchronizingObject
for definido como umaISynchronizeInvoke
instância, oElapsed
evento será executado no thread que hospeda o objeto de sincronização. Normalmente, essasISynchronizeInvoke
instâncias nada mais são do que instâncias antigasControl
e com asForm
quais estamos todos familiarizados. Portanto, nesse caso, oElapsed
evento é invocado no thread de IU e se comporta de forma semelhante aoSystem.Windows.Forms.Timer
. Caso contrário, realmente depende daISynchronizeInvoke
instância específica que foi usada.Se
SynchronizingObject
for nulo, oElapsed
evento é chamado em umThreadPool
encadeamento e se comporta de forma semelhante aoSystem.Threading.Timer
. Na verdade, ele realmente usa umSystem.Threading.Timer
nos bastidores e faz a operação de empacotamento depois de receber o retorno de chamada do cronômetro, se necessário.fonte
System.Threading.Timer
ouSystem.Timers.Timer
?System.Timers.Timer
tem dois modos de operação. Ele pode ser executado em um thread de pool de threads atribuído aleatoriamente OU pode ser executado em qualquer thread que esteja hospedando aISynchronizeInvoke
instância. Não sei como deixar isso mais claro.System.Threading.Timer
tem pouco (ou nada) a ver com a pergunta original.lock
para isso?Cada evento decorrido será disparado no mesmo encadeamento, a menos que um Elapsed anterior ainda esteja em execução.
Então ele lida com a colisão para você
tente colocar isso em um console
você vai conseguir algo assim
onde 10 é o encadeamento de chamada e 6 e 12 estão disparando do evento bg decorrido. Se você remover o Thread.Sleep (2000); você vai conseguir algo assim
Uma vez que não há colisões.
Mas isso ainda deixa você com um problema. se você está disparando o evento a cada 5 segundos e leva 10 segundos para editar, você precisa de algum bloqueio para pular algumas edições.
fonte
timer.Stop()
no início do método de evento Elapsed e, em seguida, umtimer.Start()
no final do método de evento Elapsed evitará que o evento Elapsed colida.Para System.Timers.Timer, em thread separado, se SynchronizingObject não estiver definido.
Saída que você veria se DummyTimer disparasse em um intervalo de 5 segundos:
Portanto, como visto, OnDummyTimerFired é executado no thread Workers.
Não, complicação adicional - Se você reduzir o intervalo para 10 ms,
Isso ocorre porque se a execução anterior de OnDummyTimerFired não for feita quando o próximo tique for disparado, o .NET criará um novo encadeamento para fazer esse trabalho.
Para complicar ainda mais, "a classe System.Timers.Timer fornece uma maneira fácil de lidar com esse dilema - ela expõe uma propriedade pública SynchronizingObject. Definir essa propriedade para uma instância de um formulário do Windows (ou um controle em um formulário do Windows) garantirá que o código em seu manipulador de eventos Elapsed é executado no mesmo thread em que o SynchronizingObject foi instanciado. "
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2
fonte
Se o evento decorrido demorar mais que o intervalo, será criado outro encadeamento para gerar o evento decorrido. Mas há uma solução alternativa para isso
fonte