Подтвердить что ты не робот

Выполняет ли System.Timers.Timer независимые потоки?

Я пытаюсь понять, когда System.Timers.Timer вызывает прошедшее событие, возникает ли он в независимом потоке?

В моем примере ниже показано, что три таймера работают независимо в своих потоках:

class Program
{
    static System.Timers.Timer timer = new System.Timers.Timer();
    static System.Timers.Timer timer2 = new System.Timers.Timer();
    static System.Timers.Timer timer3 = new System.Timers.Timer();

    static void Main(string[] args)
    {
        timer.Elapsed += new System.Timers.ElapsedEventHandler(
            timer_Elapsed);
        timer2.Elapsed += new System.Timers.ElapsedEventHandler(
            timer2_Elapsed);
        timer3.Elapsed += new System.Timers.ElapsedEventHandler(
            timer3_Elapsed);

        timer.Interval = 1000;
        timer2.Interval = 1000;
        timer3.Interval = 1000;

        timer.Start();
        timer2.Start();
        timer3.Start();

        Console.WriteLine("Press \'q\' to quit the sample.");
        while (Console.Read() != 'q') ;
    }

    static void timer3_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timer3.Stop();
        Console.WriteLine("Timer 3 Hit...");            
        timer3.Start();
    }

    static void timer2_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timer2.Stop();
        Console.WriteLine("Timer 2 Hit...");
        Thread.Sleep(2000);
        timer2.Start();
    }

    static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timer.Stop();
        Console.WriteLine("Timer 1 Hit...");
        Thread.Sleep(10000);
        timer.Start();
    }
}

enter image description here

4b9b3361

Ответ 1

В соответствии с MSDN, в System.Timers.Timer при срабатывании события Elapsed он вызывается в потоке в системном потоке-пуле:

Если свойство SynchronizingObject равно Nothing, событие Elapsed будет поднято в потоке ThreadPool. Если обработка события Elapsed длится дольше Interval, событие может быть снова поднято в другом потоке ThreadPool. В этой ситуации обработчик события должен быть реентерабельным.

Поскольку значение по умолчанию SynchronizingObject равно null, все ваши прошедшие события будут обрабатываться в пуле потоков. Таким образом, это зависит от того, насколько заполнен пул потоков, если есть свободные потоки, то каждое прошедшее событие может, скорее всего, работать одновременно на отдельных потоках. Если по какой-то причине системный пул потоков уже полностью задействован, возможно, прошедшие события могут быть сериализованы по мере их запланированного.

Главное: "это зависит". То есть, им будет разрешено работать параллельно, пока в пуле есть свободные потоки.

Ссылка: MSDN на System.Timers.Timer

Ответ 2

На основе вашего кода они должны быть, поскольку Thread.Sleep является блокирующим вызовом. Ни один из других таймеров не загорелся бы, если бы они работали в одном потоке.

Вы можете выводить System.Threading.Thread.CurrentThread.ManagedThreadId в каждом из них, чтобы точно знать.

Ответ 3

Это довольно сложно. В документации указано следующее:

Серверный таймер предназначен для использования с рабочими потоками в многопоточной среде. Таймеры сервера могут перемещаться между потоками для обработки поднятого события Elapsed, что приводит к большей точности, чем таймеры Windows, во время всплытия события.

а затем это:

Если свойство SynchronizingObject равно null, событие Elapsed возникает в потоке ThreadPool. Если обработка события Elapsed длится дольше Interval, событие может быть снова поднято в другом потоке ThreadPool. В этой ситуации обработчик события должен быть реентерабельным.

а затем это:

Если вы используете Таймер с элементом пользовательского интерфейса, таким как форма или элемент управления, не помещая таймер в этот элемент пользовательского интерфейса, назначьте форму или элемент управления, который содержит таймер, в свойство SynchronizingObject, так что это событие перенаправляется на поток пользовательского интерфейса.

Итак, нет простого ответа на ваш вопрос: "Он поднят в независимом потоке?" Это зависит от многих вещей.

Ответ 4

Да, каждый раз, когда вызывается Elapsed, обратный вызов запускается в своем потоке.

Кроме того, нет ничего, чтобы остановить один обработчик события Elapsed от запуска до завершения предыдущего. Например, если ваш таймер срабатывает каждые 500 миллисекунд, но код обработчика Elapsed обработчиков занимает 2 секунды, код Elapsed может иметь доступ к тем же ресурсам (небезопасные объекты, файлы и т.д.).