Приостановка
и уничтожение потоков
Пространство
имен Threading содержит и другие методы,
прерывающие нормальное
функционирование потоков:
Трудно сказать,
зачем в .NET была включена поддержка
этих методов — при вызове Suspend и Abort
программа, скорее всего, начнет
работать нестабильно. Ни один из
методов не позволяет нормально
провести деинициализацию потока.
Кроме того, при вызове Suspend или Abort
невозможно предсказать, в каком
состоянии поток оставит объекты
после приостановки или аварийного
завершения.
В результате
вызова Abort инициируется исключение
ThreadAbortException. Чтобы вы поняли, почему
это странное исключение не следует
обрабатывать в программах, мы
приводим отрывок из документации .NET
SDK:
«...При
уничтожении потока вызовом Abort
исполнительная среда инициирует
исключение ThreadAbortException. Это особая
разновидность исключений, которая
не может перехватываться
программой. При инициировании
этого исключения перед тем, как
уничтожить поток, исполнительная
среда выполняет все блоки Finally.
Поскольку в блоках Finally могут
выполняться любые действия,
вызовите Join, чтобы убедиться в
уничтожении потока».
Мораль: Abort и
Suspend использовать не рекомендуется
(а если без Suspend все же не обойтись,
возобновите приостановленный
поток методом Resume). Безопасно
завершить поток можно только путем
опроса синхронизируемой условной
переменной или вызовом метода
Interrupt, о котором говорилось выше.
Некоторые
потоки, работающие в фоновом режиме,
автоматически прекращают работу в
тот момент, когда останавливаются
другие компоненты программы. В
частности, сборщик мусора работает
в одном из фоновых потоков. Обычно
фоновые потоки создаются для
приема данных, но это делается лишь
в том случае, если в других потоках
работает код, способный обработать
полученные данные. Синтаксис: имя
потока.IsBackGround = True
Если в
приложении остались только фоновые
потоки, приложение автоматически
завершается.
Более серьезный
пример: извлечение данных из кода
HTML
Мы рекомендуем
использовать потоки лишь в том
случае, когда функциональность
программы четко делится на
несколько операций. Хорошим
примером является программа
извлечения данных из кода HTML из
главы 9. Наш класс выполняет две
операции: выборку данных с сайта
Amazon и их обработку. Перед нами
идеальный пример ситуации, в
которой многопоточное
программирование действительно
уместно. Мы создаем классы для
нескольких разных книг и затем
анализируем данные в разных
потоках. Создание нового потока для
каждой книги повышает
эффективность программы, поскольку
во время приема данных одним
потоком (что может потребовать
ожидания на сервере Amazon) другой
поток будет занят обработкой уже
полученных данных.
Многопоточный
вариант этой программы работает
эффективнее однопоточного
варианта лишь на компьютере с
несколькими процессорами или в том
случае, если прием дополнительных
данных удается эффективно
совместить с их анализом.
Как говорилось
выше, в потоках могут запускаться
только процедуры, не имеющие
параметров, поэтому в программу
придется внести небольшие
изменения. Ниже приведена основная
процедура, переписанная с
исключением параметров:
Public Sub FindRank()
m_Rank =
ScrapeAmazon()
Console.WriteLine("the rank of " & m_Name & "Is " & GetRank)
End Sub
Поскольку нам
не удастся воспользоваться
комбинированным полем для хранения
и выборки информации (написание
многопоточных программ с
графическим интерфейсом
рассматривается в последнем
разделе настоящей главы), программа
сохраняет данные четырех книг в
массиве, определение которого
начинается так:
Dim theBook(3.1) As String theBook(0.0) = "1893115992"
theBook(0.l) =
"Programming VB .NET" ' И т.д.
Четыре потока
создаются в том же цикле, в котором
создаются объекты AmazonRanker:
For i= 0 То 3
Try
theRanker = New
AmazonRanker(theBook(i.0). theBookd.1))
aThreadStart = New
ThreadStar(AddressOf theRanker.FindRan()
aThread = New Thread(aThreadStart)
aThread.Name =
theBook(i.l)
aThread.Start()
Catch e As Exception
Console.WriteLine(e.Message)
End Try
Next
Ниже приведен
полный текст программы:
Option Strict On Imports System.IO Imports System.Net
Imports System.Threading
Module Modulel
Sub Main()
Dim theBook(3.1) As
String
theBook(0.0) =
"1893115992"
theBook(0.l) =
"Programming VB .NET"
theBook(l.0) =
"1893115291"
theBook(l.l) =
"Database Programming VB .NET"
theBook(2,0) =
"1893115623"
theBook(2.1) =
"Programmer 's Introduction to C#."
theBook(3.0) =
"1893115593"
theBook(3.1) =
"Gland the .Net Platform "
Dim i As Integer
Dim theRanker As =AmazonRanker
Dim aThreadStart As Threading.ThreadStart
Dim aThread As Threading.Thread
For i = 0 To 3
Try
theRanker = New AmazonRankerttheBook(i.0). theBook(i.1))
aThreadStart = New ThreadStart(AddressOf theRanker. FindRank)
aThread = New Thread(aThreadStart)
aThread.Name= theBook(i.l)
aThread.Start()
Catch e As Exception
Console.WriteLlnete.Message)
End Try Next
Console.ReadLine()
End Sub
End Module
Public Class AmazonRanker
Private m_URL As String
Private m_Rank As Integer
Private m_Name As
String
Public Sub New(ByVal ISBN As String. ByVal theName As String)
m_URL = "ISBN
m_Name = theName End
Sub
Public Sub FindRank() m_Rank = ScrapeAmazon()
Console.Writeline("the
rank of " & m_Name & "is "
& GetRank) End
Sub
Public Readonly
Property GetRank() As String Get
If m_Rank <> 0
Then
Return CStr(m_Rank)
Else
' Проблемы
End If
End Get
End Property
Public Readonly
Property GetName() As String Get
Return m_Name
End Get
End Property
Private Function
ScrapeAmazon() As Integer Try
Dim theURL As New
Uri(m_URL)
Dim theRequest As
WebRequest
theRequest =WebRequest.Create(theURL)
Dim theResponse As
WebResponse
theResponse =
theRequest.GetResponse
Dim aReader As New
StreamReader(theResponse.GetResponseStream())
Dim theData As
String
theData = aReader.ReadToEnd
Return Analyze(theData)
Catch E As Exception
Console.WriteLine(E.Message)
Console.WriteLine(E.StackTrace)
Console. ReadLine()
End Try End Function
Private Function Analyze(ByVal theData As String) As Integer
Dim Location As.Integer Location = theData.IndexOf("<b>Amazon.com
Sales Rank:</b>")
_
+ "<b>Amazon.com Sales Rank:</b>".Length
Dim temp As String
Do Until theData.Substring(Location.l) = "<" temp = temp
&theData.Substring(Location.l)
Location += 1 Loop
Return Clnt(temp)
End Function
End Class
Многопоточные
операции часто используются в .NET и
пространствах имен ввода-вы-вода,
поэтому в библиотеке .NET Framework для
них предусмотрены специальные
асинхронные методы. Дополнительная
информация о применении
асинхронных методов при написании
многопоточных программ приведена в
описании методов BeginGetResponse и
EndGetResponse класса HTTPWebRequest