Добавить в цитаты Настройки чтения

Страница 228 из 372

              workCount++;

        }

        public static void Main() {

             int sumResult, multResult, count = 0;

             Console.WriteLine("Client thread = " +

                    Thread.CurrentThread.GetHashCode() + PoolThread = "+

                    Thread.CurrentThread.IsThreadPoolThread);

              HardFunction2Args sum =

                     new HardFunction2Args(Server.Sum);

              HardFunctionlArg mult =

                     new HardFunctionlArg(Server.MultBy2);

              AsyncCallback sumCallback =

                     new AsyncCallback(SumCallback);

              AsyncCallback multCallback =

                     new AsyncCallback(MultCallback);

              IAsyncResult arSum = sum.Beginlnvoke(3, 4,

                     out sumResult, sumCallback, sum);

               IAsyncResult arMult = mult.Beginlnvoke(5,

                      out multResult, multCallback, mult);

               while (workCount < 2) {

                       Console.WriteLine("Client thread: count = "+ count++);

                       Thread.Sleep(100);

              }

              Console.WriteLine("Bye!");

        }

}

Комментарии к коду.

Сервер и клиент представлены соответственно классами Server и Client.

Сервер

Сервер реализует два статических метода:

• Метод public static bool Sum(int x, int у, out int z) {… } обеспечивает сложение двух чисел типа int. Результат записывается в переменную z типа int. В случае возникновения переполнения возвращается false, при его отсутствии — true.

Временная сложность проводимых вычислений имитируется с помощью вызова Thread.Sleер(1000).

В самом начале, еще до проведения вычислений, на консоль выводится хеш потока, выполняющего вызов (Thread.CurrentThread.GetHashCode()), и информация о принадлежности данного потока классу рабочих потоков из пула потоков (Thread.CurrentThread.IsThreadPoolThread)).

• Метод public static bool MuitBy2(int x, out int y) {… } обеспечивает умножение числа на 2 и реализован аналогично предыдущему методу.

Здесь важно отметить, что разработчик сервера не заботится о том, как именно будут вызываться методы сервера клиентами — синхронно или асинхронно. Все зависит от клиента. Он может вызывать методы сервера как синхронно, так и асинхронно.

Клиент. Типы используемых делегатов

В данном примере клиент вызывает методы сервера асинхронно, что достигается за счет использования делегатов.

В коде клиента используются делегаты трех типов:

• HardFunction2Args

Этот тип определяется в классе client:

private delegate bool HardFunction2Args (int x, int y, out int result);

Данный делегат может делегировать вызов (как синхронный так и асинхронный) любому методу (как статическому так и нестатическому) любого класса с заданной сигнатурой (два входных параметра типа int, один выходной типа int, возвращаемое значение типа bool). В нашем случае вызов будет делегироваться методу Server::Sum.





• HardFunctionlArg

Этот тип также определяется в классе Client:

private delegate bool HardFunctionlArg (int x, out int result);

Данный делегат может делегировать вызов (как синхронный так и асинхронный) любому методу (как статическому так и нестатическому) любого класса с заданной сигнатурой (один входной параметр типа int, один выходной типа int, возвращаемое значение типа bool). В данном случае вызов будет делегироваться методу Server::MultBy2.

 AsyncCallback

Этот тип определен в System. Он может использоваться для делегирования вызова методу со следующей сигнатурой:

♦ один входной параметр типа IAsyncResult (тип определен в System);

♦ возвращаемое значение отсутствует (void).

В нашем случае делегаты данного типа будут использоваться для делегирования вызовов методам клиента Client::SumCallback и Client::MultCallback.

Метод

private static void SumCallback (IAsyncResult ar) {… }

клиента вызывается инфраструктурой асинхронных вызовов для уведомления клиента о том, что сделанный им ранее асинхронный вызов метода sum сервера завершен.

Аналогично, метод

private static void MultCallback (IAsyncResult ar) {… }

клиента вызывается инфраструктурой асинхронных вызовов для уведомления клиента о том, что сделанный им ранее асинхронный вызов метода MuitBy2 сервера завершен также.

Клиент. Инициирование асинхронных вызовов

Прежде чем обсуждать завершение асинхронных вызовов уместно рассмотреть их инициирование. Для этого обратимся к коду метода Client::Main.

Прежде всего клиент выводит на консоль хеш основного потока

(Thread. CurrentThread. GetHashCode()) и информацию о принадлежности данного потока классу рабочих потоков из пула потоков

(Thread.CurrentThread.IsThreadPoolThread)).

Далее создаются два делегата для инициирования асинхронных вызовов методов сервера. Делегат sum

HardFunction2Args sum = new HardFunction2Args(Server.Sum);

используется для асинхронного вызова метода Server::Sum, а делегат mult

HardFunctionlArg mult = new HardFunctionlArg(Server.MultBy2);

используется для асинхронного вызова метода Server::MultBy2.

Далее формируются делегаты sumCallback и multCallback

AsyncCallback sumCallback = new AsyncCallback(SumCallback);

AsyncCallback multCallback = new AsyncCallback(MultCallback);

которые будут использоваться инфраструктурой асинхронных вызовов для уведомления клиента о завершении соответственно Server::Sum и Server::MultBy2 вызовов.

Инициирование асинхронных вызовов производится клиентом следующим образом:

IAsyncResult arSum = sum.Beginlnvoke(3, 4, out sumResult, sumCallback, sum);

IAsyncResult arMult = mult.Beginlnvoke(5, out multResult, multCallback, mult);

Немного о делегатах в связи с асинхронными вызовами

Остановимся на некоторых вопросах, связанных с делегатами, имеющими отношение к асинхронным вызовам.

Делегаты sum и mult являются экземплярами ненаследуемых классов, производных от класса System.MuiticastDelegate. Система автоматически формирует эти классы, и, в том числе, реализации их методов Invoke, Begininvoke и EndInvoke. Рассмотрим, для примера, сигнатуры этих методов для делегата sum:

 public bool Invoke(int, int, out int)

Данный метод может использоваться для синхронного вызова метода Server::Sum. Первые два аргумента используются для передачи по значению суммируемых величин, последний — для передачи по ссылке результата, возвращаемое значение говорит об отсутствии переполнения.

В нашем случае этот метод будет вызван инфраструктурой асинхронных вызовов после инициирования вызова метода sum клиентом.

 public IAsyncResult Begininvoke(int, int, out int, AsyncCallback, Object)

Данный метод используется для инициирования асинхронного вызова метода Server::Sum клиентом.