Приостановка и уничтожение потоков

Пространство имен Threading содержит и другие методы, прерывающие нормальное функционирование потоков:

  • Suspend;
  • Abort.
  • Трудно сказать, зачем в .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