Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Завершение потока






Помимо уже упомянутых методов Start, Join, Sleep в классе Thread есть еще несколько десятков методов, как статических, так и динамических, вызываемых объектами - экземплярами класса Thread. Рассмотрим два метода, позволяющие завершить поток - Interrupt и Abort.

Когда поток вызывает метод Interrupt, то все зависит от того, в каком состоянии находится поток. Если поток находится в заблокированном состоянии или через некоторое время перейдет в заблокированное состояние, например, " уснет", то поток выводится из этого состояния. Вот как это происходит. Для заблокированного потока возникает исключительная ситуация ThreadInterruptedException. Управление будет передано обработчику этой ситуации и по его завершению, завершит свою жизнь и поток. Понятно, что вызов Interrupt предполагает, что предусмотрен обработчик такой ситуации. В противном случае работа приложения будет прервана, что конечно является печальным фактом.

Когда поток вызывает метод Abort, то независимо от того, в каком состоянии находится поток, он обычно завершается. При этом также возникает исключительная ситуация ThreadAbortException, для которой можно предусмотреть обработчик события. Но даже если этого обработчика нет, поток нормально завершит свою работу. В отдельных случаях при обработке исключения можно отменить уничтожение потока, вызвав метод ResetAbort.

У прерываемого потока может быть блок finally, который выполняется до прерывания потока. Поскольку завершение потока это некоторый процесс, требующий времени, то вызывающий поток, прерывающий работу дочернего потока, после вызова метода Abort вызывает метод Join, чтобы дождаться завершения потока.

class Counts

{

long sum = 0;

const long LIMIT = 100000000;

public long Sum

{

get { return sum; }

}

public void Count()

{

sum = 0;

try

{

while (sum < LIMIT)

{

sum++;

Thread.Sleep(0);

}

}

catch (ThreadInterruptedException)

{

Console.WriteLine(" Метод Count был прерван вызовом

Interrupt! ");

}

finally

{

Console.WriteLine(" Конец! ");

}

}

}

Метод на каждом шагу засыпает, так что его выполнение в потоке блокируется, и он периодически будет переходить в состояние " ожидание". Метод предусматривает обработку события Interrupt.

А теперь в процедуре Main нашего приложения создадим поток, выполняющий метод Count:

class Program

{

static void Main(string[] args)

{

//Создание и запуск потока

Thread thread_count;

Counts my_counter = new Counts();

thread_count = new Thread(my_counter.Count);

thread_count.Start();

//Засыпаем, дав потоку возможность поработать

Thread.Sleep(1);

//Просыпаемся и останавливаем работу потока

thread_count.Interrupt();

//Дожидаемся завершения потока

thread_count.Join();

//Печать результатов работы потока

Console.WriteLine(" count = " + my_counter.Sum);

}

}

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

Понятно, что произошло. Поток thread_count часто " засыпал". Когда в таком состоянии основной поток вызвал метод Interrupt, то возникла исключительная ситуация - ThreadInterruptedException, которая была обработана, после чего поток выполнил действия, указанные в блоке finally и завершил свою работу, успев немного посчитать.

Что произойдет, если поток засыпать не будет? Давайте в методе Count закомментируем оператор

Thread.Sleep(0);

Поскольку до завершения своей работы поток thread_count не блокируется, то вызов Interrupt не оказывает на него никакого воздействия, и он спокойно досчитает до максимально возможного значения LIMIT.

А что произойдет, если поток блокируется, но обработчик события ThreadInterruptedException не предусмотрен? Закомментируем обработчик события в методе Count. Для потока в заблокированном состоянии возникнет исключительная ситуация и обрабатывать ее будет системный обработчик, прерывающий работу приложения. Блок finally и в этом случае будет работать.

Для проверки работы метода завершения потока Abort добавим в класс Counts метод Count2, похожий на метод Count, но устроенный чуть сложнее, поскольку он восстанавливает свою работу в результате обработки исключительной ситуации:

public void Count2()

{

try

{

while (sum < LIMIT)

{

sum += 2;

}

}

catch (ThreadAbortException)

{

Console.WriteLine(" Не буду завершать Count2 при вызове Abort" +

" \r\n" + " Восстановлюсь и завершу свою работу!! ");

Thread.ResetAbort();

}

finally

{

Console.WriteLine(" Конец! ");

}

while (sum < LIMIT)

{

sum += 2;

}

}

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

//Создание второго потока

Thread thread_count2;

Counts my_counter2 = new Counts();

thread_count2 = new Thread(my_counter2.Count2);

thread_count2.Start();

Thread.Sleep(1);

thread_count2.Abort();

thread_count2.Join();

Console.WriteLine(" count2 = " + my_counter2.Sum);

Если закомментировать ResetAbort, то работа потока будет прервана.

Более того, можно вообще отключить обработчик события! И в этом случае поток прервет свою работу без всяких осложнений, никакой системный обработчик события вызываться не будет. Прерывание работы потока будет происходить независимо от того, будет ли поток блокирован или находится в состоянии " выполнение".

Рассмотрим ряд проблем, характерных для параллельных вычислений.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.