Потоки. MethodInvoker - делегатный тип. Передача параметров в асинхронную процедуру

Страницы работы

Фрагмент текста работы

Потоки

Потоки можно выбирать из множества потоков, управляемого классом ThreadPool. В нем существуют потоки двух типов: рабочие и потоки ввода-вывода. Мы можем управлять обоими количествами.

class Program

{

static void Main()

{

int nWorker, nAsyn;

ThreadPool.GetAvailableThreads(out nWorker, out nAsyn);

Console.WriteLine("\nWorker Threads:    {0},\n"+"Async I/O Threads: {1}\n",nWorker,nAsyn);

ThreadPool.SetMaxThreads(20, 10);

ThreadPool.GetAvailableThreads(out nWorker, out nAsyn);

Console.WriteLine("\nWorker Threads:    {0},\n"+"Async I/O Threads: {1}\n",nWorker,nAsyn);

}

}

MethodInvoker - делегатный тип

MethodInvoker представляет делегатный тип, объект которого может выполнить любой метод с сигнатурой void Func(void); в рамках нового потока, выбранного из ThreadPool. Метод Func должен быть с пустым списком параметров и не принимають параметры.

Добавим в класс Program переменную count: счетчик запусков новых потоков.

static int count = 0;

Добавим процедуру, которая будет запускать метод Func в отдельном потоке.

void CallFuncAsyncTimes ()

{

MethodInvoker mi = new MethodInvoker(Func);

for (int i = 0; i < 30; i++)

mi.BeginInvoke(null, null); // mi.Invoke();

}

Пусть метод Func выводит результаты опроса объектов ThreadPool и Thread.

void Func ()

{

int nWorker, nAsyn;

ThreadPool.GetAvailableThreads(out nWorker, out nAsyn);

Thread thread = Thread.CurrentThread;

Console.WriteLine("{0, -4} {1, -3}    {2}        {3}            {4}",

count++, thread.GetHashCode(), thread.IsThreadPoolThread, nWorker, nAsyn);

Thread.Sleep(30000);

}

В Main добавим вызов метода CallFuncAsyncTimes.

static void Main()

{

Program p = new Program();

ThreadPool.SetMaxThreads(20, 20);

Console.WriteLine("\nCallFuncAsyncTimes");

Console.WriteLine("#   ID      Pool   Worker Left  Async I/O Left\n");

p.CallFuncAsyncTimes();

Console.ReadKey();

}

Заметим, что:

¨  Все потоки выбираются из множества thread pool.

¨  При вызове Func, каждый поток получает свой ID.

¨  По исчерпании множества thread pool (после вызова 20-го потока) идентификаторы начинают повторяться. Потоки используются повторно.

¨  После вызова 20-го потока цикл for главного (primary) потока приложения ждет освобождения потока из множества pool.

¨  Как только появляется свободный поток, приложение тут же отдает его для выполнения метода Func.

Вывод: Не ныряйте очень глубоко в ThreadPool — может не хватить кислорода.

BeginInvoke и EndInvoke

BeginInvoke запускает метод и не знает, когда он закончится. Метод EndInvoke блокирует приложение и ждет завершения потока. Заметим, что BeginInvokeвозвращает ссылку на объект, реализующий интерфейс IAsyncResult.

Этот интерфейс представляет стандарт определения статуса (результата) асинхронной процедуры и способов синхронизации процедур. Он реализован классами, в которых есть методы, умеющие выполняться асинхронно. Например, FileStream.BeginRead.

Интерфейс IAsyncResult определяет такие свойства:

¨  object AsyncState { get; }  — Выдает определяемый пользователем объект, который содержит информацию о результате (или состоянии) асинхронной процедуры.

¨  bool IsCompleted { get; } — асинхронная процедура закончилась ?

¨  bool CompletedSynchronously { get; } — признак того, что асинхронная процедура завершилась синхронно. Это свойство может быть true для asynchronous I/O operation, если I/O-запрос был непродолжительным.

¨  WaitHandle AsyncWaitHandle { get; } — используется для ожидания завершения асинхронной процедуры. WaitHandle — обобщенный объект синхронизации ОС. Это базовый класс для классов, сигнализирующих о завершении процедуры, а точнее об освобождении ресурсов, занятых ею.

С помощью объекта, реализующего IAsyncResult, мы можем получить результат (или конечное состояние) асинхронной операции. Добавим метод FuncOne, который буде выполняться асинхронно.

void FuncOne() { Thread.Sleep(1000); }

Следующий метод UsingEndInvoke показывает, как получить результат с помощью свойства AsyncState. Оно присутствует в объекте, возвращаемом методом BeginInvoke, так как последний реализует интерфейс IAsyncResult.

void UsingEndInvoke()

{

MethodInvoker mi = new MethodInvoker(FuncOne);

Console.WriteLine("\nCalling BeginInvoke");

IAsyncResult res = mi.BeginInvoke(null, "My state");

mi.EndInvoke(res); // Program will block until FunсOne is complete!

string state = (string)res.AsyncState; // Once EndInvoke is complete, get the state object

Console.WriteLine("After Calling EndInvoke: " + state);

}

Заметим, что EndInvoke позволяет выловить исключения, выбрасываемые асинхронной процедурой (если поместить EndInvoke в блок try-catch). Если сделать то же самое  с BeginInvoke, то исключение не поймать. Добавим код, имитирующий исключение.

void FuncOne() { Thread.Sleep(1000); throw new Exception("Wow! Something is wrong

Похожие материалы

Информация о работе