- •1. Язык программирования c# 3
- •2. Базовые элементы .Net Framework 67
- •3. ТЕхнология .Net Remoting 144
- •Введение
- •1. Язык программирования c#
- •1.1. Платформа .Net – обзор архитектуры
- •1.2. Язык c# - общие концепции синтаксиса
- •1.3. Система типов языка c#
- •1.4. Преобразования типов
- •1.5. Идентификаторы, ключевые слова и литералы
- •1.6. Объявление переменных, полей и констант
- •1.7. Выражения и операции
- •1.8. Операторы языка c#
- •1.9. Объявление и вызов методов
- •1.10. Массивы в c#
- •1.11. Работа с символами и строками в c#
- •1.12. Синтаксис объявления класса, Поля и методы класса
- •1.13. Свойства и индексаторы
- •1.14. Конструкторы класса и Жизненный цикл объекта
- •1.15. Наследование классов
- •1.16. Перегрузка операЦий
- •1.17. Делегаты
- •1.18. События
- •1.19. Интерфейсы
- •1.20. Структуры и перечисления
- •1.21. Пространства имен
- •1.22. Генерация и обработка исключительных ситуаций
- •1.23. Нововведения в языке c# 2.0
- •1.24. Обобщенные типы (generics)
- •2. Базовые элементы .Net Framework
- •2.1. Метаданные и механизм отражения
- •2.2. Пользовательские и встроенные атрибуты
- •2.3. Пространство имен system.Collections
- •2.4. Работа с файлами и директориями
- •2.5. Использование потоков данных
- •2.6. Сериализация
- •2.7. Сериализация объектов в нестандартном формате
- •2.8. Введение в xml
- •2.9. Работа с xml-документами в .Net framework
- •2.10. МНогопоточное программирование
- •2.11. Синхронизация потоков
- •2.12. Асинхронный вызов методов
- •2.13. Состав и взаимодействие сборок
- •2.14. Конфигурирование сборок
- •3. ТЕхнология .Net Remoting
- •3.1. Домены приложений
- •3.2. Архитектура .Net Remoting
- •3.3. Активация удаленных объектов и их время жизни
- •3.4. Программная настройка Remoting
- •3.5. Удаленные Объекты с клиентской активацией
- •3.6. Настройка Remoting при помощи конфигурационных файлов
- •3.7. Хостинг распределенных приложений
- •3.8. Объекты-сообщения
- •3.9. Пользовательские канальные приемники
- •4.1. Архитектура ado.Net
- •4.2. Учебная база cd Rent
- •4.3. Соединение с базой данных
- •4.4. Выполнение команд и запросов к базе данных
- •4.5. Чтение данных и объект DataReader
- •4.6. Параметризированные запросы
- •4.7. Рассоединенный набор данных
- •4.8. Заполнение Рассоединенного набора данных
- •4.9. Объект класса DataColumn – колонка таблицы
- •4.10. Объекты класса DataRow – строки таблицы
- •4.11. Работа с объектом класса DataTable
- •4.12. DataSet и схема рассоединенного набора данных
- •4.13. Типизированные DataSet
- •4.14. Поиск и фильтрация данных в DataSet
- •4.15. Класс DataView
- •4.16. СиНхронизация набора данных и базы
- •5.1. Архитектура и общие концепции asp.Net
- •5.2. Пример aspx-страницы. Структура страницы
- •5.3. Директивы страницы
- •5.4. Класс System.Web.Ui.Page. События страницы
- •5.5. Серверные элементы управления
- •5.6. Элементы управления Web Controls
- •5.7. Проверочные элементы управления
- •5.8. Списковые элементы управления
- •5.9. Связывание данных
- •5.11. Управление состояниями в web-приложениях
- •5.12. Кэширование
- •5.13. Безопасность в web-приложениях
- •5.14. Создание пользовательских элементов управления
- •Литература
2.12. Асинхронный вызов методов
Платформа .NET содержит средства для поддержки асинхронного вызова методов. При асинхронном вызове поток выполнения разделяется на две части: в одной выполняется метод, а в другой – нормальный процесс программы. Асинхронный вызов может служить (в некоторых случаях) альтернативой использованию многопоточности явным образом.
Асинхронный вызов метода всегда выполняется посредством объекта некоторого делегата. Любой такой объект содержит два специальных метода для асинхронных вызовов – BeginInvoke() и EndInvoke(). Данные методы генерируются во время выполнения программы (как и метод Invoke()), так как их сигнатура зависит от делегата.
Метод BeginInvoke() обеспечивает асинхронный запуск. Данный метод имеет два дополнительных параметра по сравнению с описанными в делегате. Назначение первого дополнительного параметра – передать делегат, указывающий на функцию обратного вызова, выполняемую после работы асинхронного метода (функция завершения). Второй дополнительный параметр – это объект, при помощи которого функции завершения может быть передана некоторая информация. Метод BeginInvoke() возвращает объект, реализующий интерфейс IAsyncResult, при помощи этого объекта становится возможным различать асинхронные вызовы одного и того же метода.
Приведем описание интерфейса IAsyncResult:
interface IAsyncResult {
object AsyncState{ get; }
WaitHandle AsyncWaitHandle{ get; }
bool CompletedSynchronously{ get; }
bool IsCompleted{ get; }
}
Поле IsCompleted позволяет узнать, завершилась ли работа асинхронного метода. В поле AsyncWaitHandle храниться объект типа WaitHandle. Программист может вызывать методы класса WaitHandle, такие как WaitOne(), WaitAny(), WaitAll(), для контроля над потоком выполнения асинхронного делегата. Объект AsyncState хранит последний параметр, указанный при вызове BeginInvoke().
Делегат для функции завершения описан следующим образом:
public delegate void AsyncCallback(IAsyncResult ar);
Как видим, функции завершения передается единственный параметр: объект, реализующий интерфейс IAsyncResult.
Рассмотрим пример, иллюстрирующий описанные возможности.
using System;
using System.Threading; // Нужно для "усыпления" потоков
// Делегат для асинхронного метода
public delegate void Func(int x);
class MainClass {
// Этот метод делает необходимую работу
public static void Fib(int n) {
int a = 1, b = 1, res = 1;
for(int i = 3; i <= n; i++) {
res = a + b;
a = b;
b = res;
Thread.Sleep(10); // Намерено замедлим!
}
Console.WriteLine("Fib calculated: " + res);
}
public static void Main() {
Func A = new Func(Fib);
// Асинхронный вызов "выстрелил и забыл"
// У BeginInvoke() три параметра, два не используем
A.BeginInvoke(6, null, null);
// Изображаем работу
for (int i = 1; i < 10; i++) {
Thread.Sleep(20);
Console.Write(i);
}
}
}
Вывод программы:
12Fib calculated: 8
3456789
В данном приложении имеется функция для подсчета n-ного числа Фибоначчи. Чтобы эмулировать продолжительные действия, функция намеренно замедлена. После подсчета число выводится на экран. Ни функции завершения, ни возвращаемое BeginInvoke() значение не используется. Подобный метод работы с асинхронными методами называется «выстрелил и забыл» (fire and forget).
Модифицируем предыдущее приложение. Будем использовать при вызове BeginInvoke() функцию завершения, выводящую строку текста:
using System;
using System.Threading;
public delegate void Func(int x);
class MainClass {
public static void Fib(int n) { . . . }
// Это будет функция завершения
public static void Callback(IAsyncResult ar) {
// Достаем параметр
string s = (string) ar.AsyncState;
Console.WriteLine("AsyncCall is finished with " + s);
}
public static void Main() {
Func A = new Func(Fib);
// Два асинхронных вызова
A.BeginInvoke(6, new AsyncCallback(Callback), "The end");
A.BeginInvoke(8, new AsyncCallback(Callback), "Second call");
// Изображаем работу
for (int i = 1; i < 10; i++) {
Thread.Sleep(20);
Console.Write(i);
}
}
}
Вывод программы:
12Fib calculated: 8
Async Call is finished with The end
345Fib calculated: 21
Async Call is finished with Second call
6789
В рассмотренных примерах использовались такие асинхронные методы, которые не возвращают значения. В приложениях может возникнуть необходимость работать с асинхронными методами-функциями. Для этой цели предназначен метод делегата EndInvoke(). Сигнатура метода EndInvoke() определяется на основе сигнатуры метода, инкапсулированного делегатом. Во-первых, метод является функцией, тип возвращаемого значения – такой как у делегата. Во-вторых, метод EndInvoke() содержит все out- и ref- параметры делегата, а его последний параметр имеет тип IAsyncResult. При вызове метода EndInvoke() основной поток выполнения приостанавливается до завершения работы соответствующего асинхронного метода.
Изменим метод Fib() из примера. Пусть он имеет следующую реализацию:
public static int Fib(int n, ref bool overflow) {
int a = 1, b = 1, res = 1;
overflow = false;
for (int i = 3; i <= n; i++) {
res = a + b;
// Устанавливаем флаг переполнения
if (res < 0) overflow = true;
a = b;
b = res;
}
return res;
}
В следующем примере запускаются два асинхронных метода, затем приложение дожидается их выполнения и выводит результаты на экран.
using System;
using System.Threading;
// Вот такой у нас теперь делегат
public delegate int Func(int n, ref bool overflow);
class MainClass {
// Функция считает числа Фибоначчи, следя за переполнением
public static int Fib(int n, ref bool overflow) {
int a = 1, b = 1, res = 1;
overflow = false;
for(int i = 3; i <= n; i++) {
res = a + b;
// Устанавливаем флаг переполнения
if(res < 0) overflow = true;
a = b;
b = res;
}
return res;
}
public static void Main() {
bool over = false;
Func A = new Func(Fib);
// Так как отслеживаем окончание работы методов,
// сохраняем результат работы BeginInvoke()
IAsyncResult ar1 = A.BeginInvoke(10, ref over, null, null);
IAsyncResult ar2 = A.BeginInvoke(50, ref over, null, null);
// Имитируем бурную деятельность
for (int i = 1; i < 10; i++) {
Thread.Sleep(20);
Console.Write(i);
}
// Вспомнили про методы. Остановились, ждем результат
int res = A.EndInvoke(ref over, ar2);
Console.WriteLine("Result is {0}, overflowed = {1}",
res, over);
// Теперь второй метод
res = A.EndInvoke(ref over, ar1);
Console.WriteLine("Result is {0}, overflowed = {1}",
res, over);
}
}
Вывод программы:
123456789Result is -298632863, overflowed = True
Result is 55, overflowed = False
Подведем небольшой итог. Асинхронный вызов является альтернативой использования многопоточности, так как реализует ее неявно, при помощи среды исполнения. Широкий спектр настроек позволяет решать при помощи асинхронных вызовов большой круг практических задач программирования.