intVal = Interlocked.Increment(ref intVal);
В дополнение к методам Increment() и Decrement() тип Interlocked позволяет атомарно присваивать числовые и объектные данные. Например, чтобы присвоить переменной-члену значение 83, можно обойтись без явного оператора lock (или явной логики Monitor) и применить метод Interlock.Exchange():
Interlocked.Exchange(ref myInt, 83);
Наконец, если необходимо проверить два значения на предмет равенства и изменить элемент сравнения в безопасной к потокам манере, тогда допускается использовать метод Interlocked.CompareExchange():
public void CompareAndExchange()
{
// Если значение i равно 83, то изменить его на 99.
Interlocked.CompareExchange(ref i, 99, 83);
}
Программирование с использованием обратных вызовов Timer
Многие приложения нуждаются в вызове специфического метода через регулярные интервалы времени. Например, в приложении может существовать необходимость в отображении текущего времени внутри панели состояния с помощью определенной вспомогательной функции. Или, скажем, нужно, чтобы приложение эпизодически вызывало вспомогательную функцию, выполняющую некритичные фоновые задачи, такие как проверка поступления новых сообщений электронной почты. В ситуациях подобного рода можно применять тип System.Threading.Timer в сочетании со связанным делегатом по имени TimerCallback.
В целях иллюстрации предположим, что у вас есть проект консольного приложения (TimerApp), которое будет выводить текущее время каждую секунду до тех пор, пока пользователь не нажмет клавишу <Enter> для прекращения работы приложения. Первый очевидный шаг — написание метода, который будет вызываться типом Timer (не забудьте импортировать в свой файл кода пространство имен System.Threading):
using System;
using System.Threading;
Console.WriteLine("***** Working with Timer type *****\n");
Console.ReadLine();
static void PrintTime(object state)
{
Console.WriteLine("Time is: {0}",
DateTime.Now.ToLongTimeString());
}
Обратите внимание, что метод PrintTime() принимает единственный параметр типа System.Object и возвращает void. Это обязательно, потому что делегат TimerCallback может вызывать только методы, которые соответствуют такой сигнатуре. Значение, передаваемое целевому методу делегата TimerCallback, может быть объектом любого типа (в случае примера с электронной почтой параметр может представлять имя сервера Microsoft Exchange Server для взаимодействия в течение процесса). Также обратите внимание, что поскольку параметр на самом деле является экземпляром типа System.Object, в нем можно передавать несколько аргументов, используя System.Array или специальный класс либо структуру.
Следующий шаг связан с конфигурированием экземпляра делегата TimerCallback и передачей его объекту Timer. В дополнение к настройке делегата TimerCallback конструктор Timer позволяет указывать необязательный информационный параметр для передачи целевому методу делегата (определенный как System.Object), интервал вызова метода и период ожидания (в миллисекундах), который должен истечь перед первым вызовом. Вот пример:
Console.WriteLine("***** Working with Timer type *****\n");
// Создать делегат для типа Timer.
TimerCallback timeCB = new TimerCallback(PrintTime);
// Установить параметры таймера.
Timer t = new Timer(
timeCB, // Объект делегата TimerCallback.
null, // Информация для передачи в вызванный метод.
// (null, если информация отсутствует).
0, // Период ожидания перед запуском (в миллисекундах).
1000); // Интервал между вызовами (в миллисекундах).
Console.WriteLine("Hit Enter key to terminate...");
Console.ReadLine();
В этом случае метод PrintTime() вызывается приблизительно каждую секунду и не получает никакой дополнительной информации. Ниже показан вывод примера: