Российский Государственный Технологический Университет им. К.Э. Циолковского
Опубликован: 02.03.2007 | Доступ: свободный | Студентов: 5636 / 790 | Оценка: 3.96 / 3.45 | Длительность: 27:04:00
ISBN: 978-5-9556-0086-4
Лекция 15:

Потоки

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

  • Первый вариант остановки потока тривиален. Поток завершается после выполнения ПОСЛЕДНЕГО оператора выполняемой цепочки операторов. Допустим, в ходе выполнения условного оператора значение некоторой переменной сравнивается с фиксированным значением и в случае совпадения значений управление передается оператору return:
    for (x=0;;x++)
     {
     if (x==max)
     return; // Все. Этот оператор оказался последним.
     else
     {
      ::::::::::
      } 
     }
  • Поток может быть остановлен в результате выполнения метода Abort(). Эта остановка является достаточно сложным делом.
    1. При выполнении этого метода происходит активация исключения ThreadAbortException. Естественно, это исключение может быть перехвачено в соответствующем блоке catch. Во время обработки исключения допустимо выполнение самых разных действий, которые осуществляются в этом самом "остановленном" потоке. В том числе возможна и реанимация остановленного потока путем вызова метода ResetAbort().
    2. При перехвате исключения CLR обеспечивает выполнение операторов блоков finally, которые выполняются все в том же потоке.

      Таким образом, остановка потока путем вызова метода Abort не может рассматриваться как НЕМЕДЛЕННАЯ остановка выполнения потока:

      using System;
       using System.Threading;
      
      public class ThreadWork 
       {
       public static void DoWork() 
       {
       int i;
      
      try 
       {
        for(i=0; i<100; i++) 
        {
           //4. Вот скромненько так работает...
           //   Поспит немножко – а потом опять поработает.
           //   Take Your time! 100 раз прокрутиться надо 
           //   вторичному потоку до нормального завершения.
           Console.WriteLine("Thread – working {0}.", i); 
          Thread.Sleep(10);
          }
       }
       catch(ThreadAbortException e) 
       {
        //6.
        //– Ну дела! А где это мы...
        Console.WriteLine("Thread – caught ThreadAbortException – resetting.");
        Console.WriteLine("Exception message: {0}", e.Message);
        //  (Голос сверху)
        //– Вы находитесь в блоке обработки исключения, связанного с
        //  непредвиденным завершением потока.
        //– Понятно... Значит, не успели. "Наверху" сочли нашу деятельность
        //  нецелесообразной и не дали (потоку) завершить до конца начатое дело!
        Thread.ResetAbort();
        //   (Перехватывают исключение и отменяют остановку потока)
        //   Будем завершать дела. Но будем делать это как положено,
        //   а не в аварийном порядке. Нам указали на дверь, но мы
        //   уходим достойно!
        //   (Комментарии постороннего)  
        //   А чтобы стал понятен альтернативный исход – надо
        //   закомментировать строку с оператором отмены остановки потока. 
       }
       finally
       {
        //7.
        //– Вот где бы мы остались, если бы не удалось отменить
        // остановку потока! finally блок... Отстой! 
       Console.WriteLine("Thread – in finally statement.");
       }
       //8. 
       // – А вот преждевременный, но достойный уход.
       //   Мы не довели дело до конца только потому, что нам не дали
       //   сделать этого. Обстоятельства бывают выше. Уходим достойно. 
      Console.WriteLine("Thread – still alive and working."); 
      Console.WriteLine("Thread – finished working.");
       }
       }
      
      class ThreadAbortTest 
       {
       public static void Main() 
       {
       //1. Мероприятия по организации вторичного потока!
       ThreadStart myThreadDelegate = new ThreadStart(ThreadWork.DoWork);
       Thread myThread = new Thread(myThreadDelegate);
       //2. Вторичный поток стартовал!
       myThread.Start();
      
       //3. А вот первичный поток – самоусыпился!
       //   И пока первичный поток спит, вторичный поток – работает!
       Thread.Sleep(50);
      
       //5. Но вот первичный поток проснулся – и первое, что он
       //   делает, – это прерывает вторичный поток! 
      Console.WriteLine("Main – aborting my thread.");
       myThread.Abort();
      
       //9. А в столицах тоже все дела посворачивали... 
      Console.WriteLine("Main ending."); 
       }
       }
      Листинг 15.5.

Метод Join()

Несколько потоков выполняются "параллельно" в соответствии с предпочтениями планировщика потоков. Нестатический метод Join() позволяет изменить последовательность выполнения потоков многопоточного приложения. Метод Join() выполняется в одном из потоков по отношению к другому потоку.

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

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

using System;
 using System.Threading;

public class ThreadWork 
 {
 public static void DoWork() 
 {
 for(int i=0; i<10; i++) 
 {
 Console.WriteLine("Thread – working."); 
Thread.Sleep(10);
 }

Console.WriteLine("Thread – finished working.");
 }
 }

class ThreadTest 
 {
 public static void Main() 
 {
 ThreadStart myThreadDelegate = new ThreadStart(ThreadWork.DoWork);
 Thread myThread = new Thread(myThreadDelegate);
 myThread.Start();
 Thread.Sleep(100);
 myThread.Join(); // Закомментировать вызов метода и осознать разницу.
 Console.WriteLine("Main ending."); 
 }
 }

Состояния потока (перечисление ThreadState)

Класс ThreadState определяет набор всех возможных состояний выполнения для потока. После создания потока и до завершения он находится по крайней мере в одном из состояний. Потоки, созданные в общеязыковой среде выполнения, изначально находятся в состоянии Unstarted, в то время как внешние потоки, приходящие в среду выполнения, находятся уже в состоянии Running. Потоки с состоянием Unstarted переходят в состояние Running при вызове метода Start. Не все комбинации значений ThreadState являются допустимыми; например, поток не может быть одновременно в состояниях Aborted и Unstarted.

В следующей таблице перечислены действия, вызывающие смену состояния.

Действие Состояние потока
Поток создается в среде CLR Unstarted
Поток вызывает метод Start Running
Поток начинает выполнение Running
Поток вызывает метод Sleep WaitSleepJoin
Поток вызывает метод Wait для другого объекта WaitSleepJoin
Поток вызывает метод Join для другого потока WaitSleepJoin
Другой поток вызывает метод Interrupt Running
Другой поток вызывает метод Suspend SuspendRequested
Поток отвечает на запрос метода Suspend Suspended
Другой поток вызывает метод Resume Running
Другой поток вызывает метод Abort AbortRequested
Поток отвечает на запрос метода Abort Stopped
Поток завершен Stopped

Начальное состояние потока (если это не главный поток), в котором он оказывается непосредственно после его создания, – Unstarted. В этом состоянии он пребывает до тех пор, пока вызовом метода Start() не будет переведен в состояние Running.

В дополнение к вышеперечисленным состояниям существует также Background – состояние, которое указывает, выполняется ли поток на фоне или на переднем плане.

Свойство Thread.ThreadState потока содержит текущее состояние потока. Для определения текущего состояния потока в приложении можно использовать битовые маски. Пример условного выражения:

if((myThread.ThreadState & (ThreadState.Stopped | ThreadState.Unstarted))==0) {...}

Члены перечисления:

Имя члена Описание Значение
Running Поток был запущен, он не заблокирован, и нет задерживающегося объекта ThreadAbortException 0
StopRequested Поток запрашивается на остановку. Это только для внутреннего использования 1
SuspendRequested Запрашивается приостановка работы потока 2
Background Поток выполняется как фоновый, что является противоположным к приоритетному потоку. Это состояние контролируется заданием свойства Thread.IsBackground 4
Unstarted Метод Thread.Start не был вызван для потока 8
Stopped Поток остановлен 16
WaitSleepJoin Поток заблокирован в результате вызова к методам Wait, Sleep или Join 32
Suspended Работа потока была приостановлена 64
AbortRequested Метод Thread.Abort был вызван для потока, но поток еще не получил задерживающийся объект System.Threading.ThreadAbortException, который будет пытаться завершить поток 128
Aborted Поток находится в Stopped -состоянии 256

Ниже приводится диаграмма состояний потока.


kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2