Для System.Timers.Timer, в окремому потоці, якщо SynchronizingObject не встановлено.
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;
}
Вихідні дані, які ви побачите, якщо DummyTimer спрацював через 5 секунд:
Main Thread Id: 9
12
12
12
12
12
...
Отже, як видно, OnDummyTimerFired виконується в потоці Workers.
Ні, подальше ускладнення - якщо ви зменшите інтервал до 10 мс,
Main Thread Id: 9
11
13
12
22
17
...
Це пов’язано з тим, що якщо попереднє виконання OnDummyTimerFired не буде виконано під час запуску наступного галочки, тоді .NET створить новий потік для виконання цієї роботи.
Ще більше ускладнюючи ситуацію, "Клас System.Timers.Timer пропонує простий спосіб вирішити цю дилему - він відкриває загальнодоступну властивість SynchronizingObject. Встановлення цієї властивості для екземпляра форми Windows (або елемента керування у формі Windows) забезпечить що код у вашому обробнику подій Elapsed працює в тому самому потоці, у якому був створений екземпляр SynchronizingObject. "
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2