Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Многопоточность.doc
Скачиваний:
4
Добавлен:
28.10.2018
Размер:
225.79 Кб
Скачать

Методы создания потоков

Здесь описаны основные методы создания потоков в .NET Framework.

Делегаты

Наверное наиболее простым методом выполнения какого-либо метода в отдельном потоке является использование делегата (программа ThreadingDelegate). Пусть у нас есть метод, выполняющий какую-либо длительную задачу:

private void CheckPrimeNumber(long checkNumber){…}

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

private delegate void CheckPrimeNumberDelegate(long checkNumber);

Затем создайте объект делегата, передав его конструктору ваш метод, который вы хотите выполнить в отдельном потоке:

CheckPrimeNumberDelegate dlgt = new CheckPrimeNumberDelegate(CheckPrimeNumber);

Запуск выполнения метода в новом потоке осуществляется вызовом метода BeginInvoke делегата.

dlgt.BeginInvoke(1000000021, null, null);

Этому методу передаются те же параметры, что передавались бы методу CheckPrimeNumber, а так же некоторые другие. Вот и все. Ваш метод будет выполнен в отдельном потоке, не останавливая выполнение основного потока.

Ожидание завершения работы потока

Рассмотренный нами случай был наиболее простым. Однако предположим, что наш метод, который должен выполняться в отдельном потоке, возвращает некоторый результат:

private static long GetDivider(long checkNumber){…}

Очевидно, нам необходимо знать две вещи:

  • Когда поток завершил работу?

  • Как получить результат, возвращенный функцией, выполнявшейся в этом потоке?

Рассмотрим решение первой задачи. Как и в предыдущем случае необходимо создать делегат, соответствующий нашему методу, создать его экземпляр и вызвать метод BeginInvoke.

private delegate long GetDividerDelegate(long checkNumber);

GetDividerDelegate dlgt = new GetDividerDelegate(GetDivider);

Однако теперь нас интересует объект, возвращаемый методом BeginInvoke:

IAsyncResult res = dlgt.BeginInvoke(1000000021, null, null);

Первый способ дождаться завершения созданного нами потока – проверять свойство IsCompleted объекта IAsyncResult:

while (!res.IsCompleted)

{

continue;

}

Внутри данного цикла вы можете производить какую-либо работу в основном потоке.

Второй подход заключается в использовании объекта, возвращаемого свойством AsyncWaitHandle объекта IAsyncResult:

res.AsyncWaitHandle.WaitOne();

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

В связи с этим наверно самым удобным способом получения уведомления о том, что ваш поток завершился, является делегат обратного вызова. Этот делегат передается одним из параметров метода BeginInvoke:

dlgt.BeginInvoke(1000000021, new AsyncCallback(GetDividerFinished), null);

Сигнатура этого метода:

private static void GetDividerFinished(IAsyncResult res){…}

Как видно, ему передается такой же объект IAsyncResult, что возвращался при вызове метода BeginInvoke. При использовании такого подхода основной поток не будет заблокирован, а в момент завершения вашего потока будет вызван метод GetDividerFinished.