Определение делегатов в качестве статических членов

В С# можно определять метод, который используется при создании делегата как статический член класса.

Составные делегаты

Объединение делегатов — создание одного делегата из нескольких.

Эта возможность языка позволяет динамически определять, какие методы нужно включать в метод обратного вызова, и объединять их в составной делегат. Исполняющая среда распознает, что эти методы нужно вызвать последовательно.

Определение событий с помощью делегатов

Работа с событиями в С# соответствует модели "издатель — подписчик", где класс публикует событие, которое он может инициировать, и любые классы могут подписаться на это событие. При инициации события исполняющая среда следит за тем, чтобы уведомить всех подписчиков о возникновении события.

Метод, вызываемый при возникновении события, определяется делегатом. Однако нужно помнить об ограничениях. Во-первых, нужно чтобы такой делегат принимал два аргумента. Во-вторых, эти аргументы всегда должны представлять два объекта: тот, что инициировал событие (издатель), и информационный объект события, который должен быть производным от класса EventArgs .NET Framework.

Интерфейсы

Интерфейсы определяются с помощью ключевого слова interface, как показано в следующем примере.

interface IEquatable<T>

{ bool Equals(T obj);}

Интерфейсы описывают группу связанных функциональных возможностей, которые могут принадлежать к любому классу или структуре. Интерфейсы в могут содержать методы, свойства, события, индексаторы или любое сочетание этих перечисленных типов членов. Интерфейсы не могут содержать поля. Члены интерфейсов автоматически являются открытыми.

Классы и структуры могут быть унаследованы от интерфейсом таким же образом, как классы могут быть унаследованы от базового класса или структуры, но есть два исключения:

· Класс или структура может наследовать несколько интерфейсов.

· Когда класс или структура наследует интерфейс, наследуются только имена и подписи методов, поскольку сам интерфейс не содержит реализаций.

Для реализации члена интерфейса соответствующий член класса должен быть открытым и не статическим, он должен обладать таким же именем и подписью, как член интерфейса.

Интерфейс имеет следующие свойства.

· Интерфейс подобен абстрактному базовому классу: любой неабстрактный тип, наследующий интерфейс, должен реализовать все его члены.

· Невозможно создать экземпляр интерфейса напрямую.

· Интерфейсы могут содержать методы, свойства, индексаторы и события в качестве членов.

· Интерфейсы не содержат реализации методов.

· Как классы, так и структуры способны наследовать от нескольких интерфейсов.

· Интерфейс может быть унаследован от нескольких интерфейсов.


Программирование многопоточности. Потоки и многозадачность. Переключение контекста. Безопасность и синхронизация потоков.

Потоки и многозадачность

 

Поток является единицей обработки данных, а многозадачность — это одновременное исполнение нескольких потоков. Существует два вида многозадачности — совместная (cooperative) и вытесняющая (preemptive). При этом процессор отвечает за выдачу каждому потоку определенного количества времени, в течение которого поток может выполняться, — кванта времени (timeslice). Далее процессор переключается между разными потоками, выдавая каждому потоку его квант времени.

Кстати, даже в случае вытесняющей многозадачности, если вы работаете на однопроцессорной машине, то все равно в любой момент времени реально будет исполняться только один поток. Поскольку интервалы между переключениями процессора от процесса к процессу измеряются миллисекундами, возникает иллюзия многозадачности. Чтобы несколько потоков на самом деле работали одновременно, вам потребуется работать на многопроцессорной машине, создав соответствующую программу.

Переключение контекста

Неотъемлемый атрибут потоков — переключение контекста (context switching)

Процессор с помощью аппаратного таймера определяет момент окончания кванта, выделенного для данного потока. Когда аппаратный таймер генерирует прерывание, процессор сохраняет в стеке содержимое всех регистров для данного потока. Затем процессор перемещает содержимое этих же регистров в структуру данных CONTEXT. При необходимости переключения обратно на поток, выполнявшийся прежде, процессор выполняет обратную процедуру и восстанавливает содержимое регистров из структуры CONTEXT, ассоциированной с потоком. Весь этот процесс называется переключением контекста.

Многопоточное приложение на С#

using System.Threading;

class SimpleThreadApp {

Public static void WorkerThreadMethodQ

{Console.WriteLine("Worker thread started");}

public static void Main() {

ThreadStart worker = new ThreadStart(WorkerThreadMethod);

Console.WriteLine("Main - Creating worker thread");

Thread t = new Thread(worker); t.StartQ;

Console.WriteLine("Main - Have requested the start of worker thread"); } }

Скомпилировав и запустив это приложение, вы увидите, что сообщение метода Main выводится перед сообщением рабочего потока. Это доказывает, что рабочий поток действительно работает асинхронно. Проанализируем происходящие здесь события.

ThreadStart — это делегат. Именно он должен быть задействован при создании нового потока. Он используется, чтобы задать метод, который должен вызываться как метод потока. Здесь я создаю экземпляр объекта Thread, при этом конструктор принимает в качестве аргумента только делегат ThreadStart:

Thread t = new Thread(worker);

После этого я вызываю метод Start объекта Thread, в результате чего вызывается метод WorkerThreadMethod.

Работа с потоками

Создание потоков и управление ими осуществляется с помощью класса System. Threading. Thread. С него мы и начнем.

В .NET потоки работают в сущности под названием AppDomain: это логический процесс внутри физического процесса.

Класс Thread

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