Главная страница

лабараторная работа. Теория_к_лабораторным. 1. Применение параллельных вычислений


Скачать 0.7 Mb.
Название1. Применение параллельных вычислений
Анкорлабараторная работа
Дата24.10.2021
Размер0.7 Mb.
Формат файлаdoc
Имя файлаТеория_к_лабораторным.doc
ТипДокументы
#254886
страница4 из 9
1   2   3   4   5   6   7   8   9

5. Асинхронный вызов делегата


Еще одним очень простым в реализации способом выполнить что-либо в параллельном по отношению к основным вычислениям потоке является асинхронный вызов делегата. Для этого группируем код, который предполагается исполнять параллельно в отдельный метод, объявляем соответствующий по сигнатуре делегат, и присваиваем экземпляру этого делегата ссылку на наш метод. Оказывается, у делегата уже есть все необходимое, чтобы выполнить асинхронный вызов переданного ему метода, вернуть управление основному потоку, и после того, как основной поток завершит то, для чего ему управление было передано, дождаться окончания выполнения параллельных вычислений.

Есть один нюанс: параллельные вычисления могут закончиться как позже основных, так и раньше. С первым случаем все понятно – мы дожидаемся их окончания вызовом метода EndEnvoke(). Во втором случае параллельный поток может сообщить о своем досрочном завершении посредством обратного вызова. В приведенном примере метод MyReport() вызывается параллельно. Методу BeginEnvoke() делегата, осуществляющего асинхронный вызов MyReport(), помимо параметра IterationsCount, передается указатель на метод MyReportCompleted(), который и будет вызван по окончанию “формирования отчета”. Важно учесть, что метод обратного вызова будет вызван в параллельном потоке, а значит нужно быть аккуратным при обновлении элементов пользовательского интерфейса и действовать по аналогии с предыдущим шагом: использовать свойство InvokeRequired и метод Invoke().


Пример работы программы с асинхронным вызовом делегата.

//Пример 3. Асинхронный вызов делегата

//Объявление делегата

private delegate void MyReportDelegate(int _IterationsCount);

//Вызов асинхронного делегата

private void btnASDInvoke_Click(object sender, EventArgs e)

{

int _IterationsCount = Convert.ToInt32(numericUpDownWork.Value);

//Начало обработки в параллельном потоке

MyReportDelegate _invoke = MyReport;

//В качестве параметра передается метод, который будет вызван по окончанию работы MyReport

IAsyncResult _invokeResult = _invoke.BeginInvoke(_IterationsCount, MyReportCompleted, this);

//'Обнуление' протокола

this.ASDLog = string.Empty;

//Параллельная MyReport обработка...

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

{

this.ASDLog = this.ASDLog + "Другая работа... "

+ Math.Round((100 * (double)(i + 1) / _IterationsCount), 2).ToString()

+ "%" + Environment.NewLine;

Thread.Sleep(10);

}

this.ASDLog = this.ASDLog + "Другая работа завершена." + Environment.NewLine;

//Дожидаемся окончания обработки MyReport

_invoke.EndInvoke(_invokeResult);

//Вывод протокола обработки

textBoxASDInvokeLog.Text = this.ASDLog + "Все работы завершены." + Environment.NewLine;

}

//Формирование отчета

private void MyReport(int _IterationsCount)

{

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

{

this.ASDLog = this.ASDLog + "Формирование отчета... "

+ Math.Round((100 * (double)(i + 1) / _IterationsCount), 2).ToString()

+ "%" + Environment.NewLine;

Thread.Sleep(10);

}

}

//Завершение формирования отчета

private void MyReportCompleted(object state)

{

textBoxASDInvokeLog.Text = textBoxASDInvokeLog.Text + "!";

this.ASDLog = this.ASDLog + "Формирование отчета завершено." + Environment.NewLine;

}

И еще один момент. Ниже приведен фрагмент кода, реализующий свойство ASDLog, доступ к которому необходимо разделять между потоками. Разделяемый ресурс, в первую очередь, необходимо оградить от одновременной корректировки несколькими потоками, а в предоставлении доступа на чтение нескольким потокам сразу нет ничего криминального. Но, если доступ на чтение вообще никак не ограничивать, то может случиться ситуация, когда во время изменения ресурса кто-то попытается его прочитать. Исход этой ситуации непредсказуем, и все зависит от природы ресурса. Экземпляры класса ReaderWriterLockSlimпомогают решить задачу оптимизации потокобезопасного доступа к ресурсу: они позволяют его читать нескольким потокам сразу, но, если один из потоков получил доступ на редактирование, то все “читатели” на время редактирования блокируются.

//Протокол обработки

private string m_ASDLog = string.Empty;

//Потокобезопасная блокировка, оптимизированная для чтения

private ReaderWriterLockSlim m_ASDLogLock = new ReaderWriterLockSlim();

//Свойство "Протокол обработки", использующее ReaderWriterLockSlim

internal string ASDLog

{

get

{

m_ASDLogLock.EnterReadLock();

try

{

return m_ASDLog;

}

finally

{

m_ASDLogLock.ExitReadLock();

}

}

set

{

m_ASDLogLock.EnterWriteLock();

try

{

m_ASDLog = value;

}

finally

{

m_ASDLogLock.ExitWriteLock();

}

}

}
1   2   3   4   5   6   7   8   9


написать администратору сайта