Таймеры

Еще одна точка входа в пул потоков находится в объектах класса Timer из пространства имен System.Threading. С его помощью можно настроить пул потоков на вызов делегата в определенное время или через регулярные интервалы. Рассмотрим пример использования объекта Timer:

1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
using System.Threading;
public class EntryPoint {
private static void TimerProc ( object state )  {
Console.WriteLine ( "Текущее время {0} на потоке {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadld ) ; 
Thread.Sleep ( 3000 ) ;
}
static void Main()  {
Console.WriteLine ( "Нажмите <Enter> для завершения\n\n" );
Timer myTimer = new Timer( new TimerCallback(EntryPoint.TimerProc), null, 0, 2000 );
Console.ReadLine (); 
myTimer.Dispose ();
}

При создании таймеру необходимо предоставить делегат, который должен быть вызван в заданное время. Для этой цели создан делегат TimerCallback, указывающий на статический метод TimerProc. Вторым параметром конструктора Timer является произвольный объект состояния, который можно передать ему.

Когда происходит обратный вызов таймера, ему передается этот объект состояния. В рассматриваемом примере объект состояния не нужен, поэтому на его месте передается null. Последние два параметра конструктора определяют, когда должен произойти обратный вызов. Предпоследний параметр указывает, когда таймер должен сработать в первый раз.

Передача значения 0 говорит о том, что таймер должен быть запущен немедленно. Последний параметр — период, через который должен произойти следующий вызов. В примере запрошен двухсекундный период. Если таймер не должен запускаться периодически, в последнем параметре необходимо передать Timeout.Infinite. И, наконец, для останова таймера нужно вызвать его метод Dispose.

Может возникнуть вопрос о том, зачем производится вызов Sleep внутри метода TimerProc. Это делается просто в целях иллюстрации, для того, чтобы показать, что TimerProc вызывает произвольный поток. Поэтому любой код, который выполняется в результате запуска делегата TimerCallback, должен быть безопасным в отношении потоков.

В рассматриваемом примере первый поток из пула, вызывающий TimerProc, находится в спящем состоянии дольше, чем длительность следующего таймаута, поэтому пул потоков вызывает TimerProc двумя секундами позже из другого потока, как видно из сгенерированного вывода. Увеличив период сна в TimerProc, можно действительно вызвать некоторое напряжение в пуле потоков.

Если когда-либо приходилось использовать класс Timer из пространства имен System.Windows.Forms, то должно быть понятно, что он существенно отличается от класса Timer из пространства System.Threading, например, Forms.Timer основан на системе обмена сообщениями Win32, а именно — на сообщении WM_TIMER.

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

Поэтому, естественно, Threading.Timer — более мощный инструмент в том смысле, что он не страдает такой зависимостью. Однако его недостатком можно считать необходимость кодирования обратных вызовов для Threading.Timer в безопасной в отношении потоков манере.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100