Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
IAsyncResult arMult = mult.Beginlnvoke(5, out multResult, multCallback, mult);
Немного о делегатах в связи с асинхронными вызовами
Остановимся на некоторых вопросах, связанных с делегатами, имеющими отношение к асинхронным вызовам.
Делегаты sum и mult являются экземплярами ненаследуемых классов, производных от класса System.MuiticastDelegate. Система автоматически формирует эти классы, и, в
• public bool Invoke(int, int, out int)
Данный метод может использоваться для синхронного вызова метода Server::Sum. Первые два аргумента используются для передачи по значению суммируемых величин, последний — для передачи по ссылке результата, возвращаемое значение говорит об отсутствии переполнения.
В нашем случае этот метод будет вызван инфраструктурой асинхронных вызовов после инициирования вызова метода sum клиентом.
• public IAsyncResult Begininvoke(int, int, out int, AsyncCallback, Object)
Данный метод используется для инициирования асинхронного вызова метода Server::Sum клиентом.
Смысл первых трех параметров описан в предыдущем пункте.
Четвертый параметр служит для передачи ссылки на делегат типа AsyncCallback, который будет использоваться инфраструктурой асинхронных вызовов для вызова callback функции на стороне клиента для уведомления последнего о завершении вызова. Этот параметр может быть задан как null. В этом случае клиент может использовать другие способы получения уведомления о завершении вызова.
Последний параметр задает ссылку на некоторый объект, которая будет доступна из объекта, полученного как результат инициирования асинхронного метода. В данном случае мы будем тут задавать ссылку на делегат sum. Это позволит клиенту в рамках callback функции SumCallback получить доступ к делегату sum и завершить асинхронный вызов, вызвав метод EndInvoke. Если callback функция не используется, этот параметр можно задать равным null.
Возвращаемое значение типа IAsyncResult дает клиенту ссылку на объект, который может использоваться последним для получения информации о выполнении асинхронного вызова. В частности, свойство bool Completed {get; } интерфейса IAsyncResult может использоваться клиентом для опроса инфраструктуры асинхронных вызовов — возвращаемое значение равно true, если вызов завершен. Это один из способов получить информацию о завершении асинхронного вызова без использования callback функции.
• public bool EndInvoke(out int, IAsyncResult)
Данный метод вызывается клиентом для завершения асинхронного вызова Server::Sum и получения результатов. В нашем случае вызов этого метода выполняется в callback функции SumCallback.
Первый параметр — результат операции сложения, возвращаемое логическое значение равно true, если в процессе вычислений не произошло переполнения.
Последний параметр типа IAsyncResult задается клиентом. Это ссылка, полученная клиентом в результате инициирования асинхронного вызова путем вызова метода BeginInvoke.
Клиент. Обработка уведомления о завершении асинхронного вызова
Теперь, обсудив механизм инициирования асинхронного вызова, следует рассмотреть вопрос о обработке уведомления о его завершении. Остановимся для примера на методе
private static void SumCallback(IAsyncResult ar) {… }
Этот метод вызывается инфраструктурой асинхронных вызовов по завершении асинхронного вызова, инициированного в Client::Main следующим образом:
IAsyncResult arSum = sum.Beginlnvoke(3, 4, out sumResult, sumCallback, sum);
В результате в качестве единственного параметра в SumCallback передается ссылка ajrSum на объект типа IAsyncResult, содержащий необходимую клиенту информацию о выполненном асинхронном вызове.
Прежде всего клиент использует полученную ссылку для получения ссылки на делегат sum:
HardFunction2Args sum = (HardFunction2Args)ar.AsyncState;
Далее клиент получает результаты завершенного асинхронного вызова
bool result = sum.Endlnvoke(out z, ar);
и выводит их на консоль
if (result) Console.WriteLine ("SumCallback: Sum = " + z);
else Console.WriteLine("SumCallback: Bad arguments for Server.Sum");
Все завершается увеличением на 1 статического счетчика workCount, служащего для подсчета числа выполненных асинхронных вызовов.
Клиент. Что он делает полезного во время ожидания
Вернемся снова к коду в Client::Main. Непосредственно после строк, инициирующих асинхронные вызовы, идет следующий код:
while (workCount < 2) {
Console.WriteLine("Client thread: count = "+ count++);
Thread.Sleep(100);
}
Именно тут клиент выполняет некоторую работу в ожидании завершения обоих асинхронных вызовов. До тех пор, пока счетчик числа завершенных асинхронных вызовов workCount не достигнет значения 2, клиент выводит на консоль очередное положительное целое с интервалом в 100 тс.