| Россия | 
Работа с потоками
В системах с общей памятью, включая многоядерные архитектуры, параллельные вычисления могут выполняться как при многопроцессном выполнении, так и при многопоточном выполнении. Многопроцессное выполнение подразумевает оформление каждой подзадачи в виде отдельной программы (процесса). Недостатком такого подхода является сложность взаимодействия подзадач. Каждый процесс функционирует в своем виртуальном адресном пространстве, не пересекающемся с адресным пространством другого процесса. Для взаимодействия подзадач необходимо использовать специальные средства межпроцессной коммуникации (интерфейсы передачи сообщений, общие файлы, объекты ядра операционной системы).
Потоки позволяют выделить подзадачи в рамках одного процесса. Все потоки одного приложения работают в рамках одного адресного процесса. Для взаимодействия потоков не нужно применять какие-либо средства коммуникации. Потоки могут непосредственно обращаться к общим переменным, которые изменяют другие потоки. Работа с общими переменными приводит к необходимости использования средств синхронизации, регулирующими порядок работы потоков с данными.
Потоки являются более легковесной структурой по сравнению с процессами ("облегченные" процессы). Поэтому параллельная работа множества потоков, решающих общую задачу, более эффективна в плане временных затрат, чем параллельная работа множества процессов.
Структура потока
Поток состоит из нескольких структур. Ядро потока – содержит информацию о текущем состоянии потока: приоритет потока, программный и стековый указатели. Программный и стековые указатели образуют контекст потока и позволяют восстановить выполнение потока на процессоре. Блок окружения потока - содержит заголовок цепочки обработки исключений, локальное хранилище данных для потока и некоторые структуры данных, используемые интерфейсом графических устройств (GDI) и графикой OpenGL. Стек пользовательского режима – используется для передаваемых в методы локальных переменных и аргументов. Стек режима ядра - используется, когда код приложения передает аргументы в функцию операционной системы, находящуюся в режиме ядра. Ядро ОС вызывает собственные методы и использует стек режима ядра для передачи локальных аргументов, а также для сохранения локальных переменных.
Состояния потоков
Каждый поток может находиться в одном из нескольких состояний. Поток, готовый к выполнению и ожидающий предоставления доступа к центральному процессору, находится в состоянии "Готовый". Поток, который выполняется в текущий момент времени, имеет статус "Выполняющийся". При выполнении операций ввода-вывода или обращений к функциям ядра операционной системы, поток снимается с процессора и находится в состоянии "Ожидает". При завершении операций ввода-вывода или возврате из функций ядра поток помещается в очередь готовых потоков. При переключении контекста поток выгружается и помещается в очередь готовых потоков.
Переключение контекста
- Значения регистров процессора для исполняющегося в данный момент потока сохраняются в структуре контекста, которая располагается в ядре потока.
 - Из набора имеющихся потоков выделяется тот, которому будет передано управление. Если выбранный поток принадлежит другому процессу, Windows переключает для процессора виртуальное адресное пространство.
 - Значения из выбранной структуры контекста потока загружаются в регистры процессора.
 
Работа с потоками в C#
Среда исполнения .NET CLR предоставляет возможность работы с управляемыми потоками через объект Thread пространства имен System.Threading. Среда исполнения стремится оптимизировать работу управляемых потоков и использовать для их выполнения потоки процесса, существующие на уровне операционной системы. Поэтому создание потоков типа Thread не всегда сопряжено с созданием потоков процесса.
Основные этапы работы
// Инициализация потока Thread oneThread = new Thread(Run); // Запуск потока oneThread.Start(); // Ожидание завершения потока oneThread.Join();
В качестве рабочего элемента можно использовать метод класса, делегат метода или лямбда-выражение. В следующем фрагменте создаются три потока. Первый поток в качестве рабочего элемента принимает статический метод LocalWorkItem. Второй поток инициализируется с помощью лямбда-выражения, третий поток связывается с методом общедоступного класса.
 class Program  
 { 
   static void LocalWorkItem() 
   { 
     Console.WriteLine("Hello from static method"); 
   } 
   static void Main() 
   { 
     Thread thr1 = new Thread(LocalWorkItem); 
     thr1.Start(); 
     Thread thr2 = new Thread(() => 
       { 
         Console.WriteLine("Hello from 
                 lambda-expression"); 
       }); 
     thr2.Start(); 
     ThreadClass thrClass = new  ThreadClass("Hello from thread-class"); 
     Thread thr3 = new Thread(thrClass.Run); 
     thr3.Start(); 
   } 
 } 
 class ThreadClass 
 { 
   private string greeting; 
   public ThreadClass(string sGreeting)  
   {  
     greeting = sGreeting; 
   } 
   public void Run() 
   { 
     Console.WriteLine(greeting); 
   } 
 } 
  Вызов метода thr1.Join() блокирует основной поток до завершения работы потока thr1.
 Thread thr1 = new Thread(() => 
   { 
     for(int i=0; i<5; i++) 
       Console.Write("A"); 
   }); 
 Thread thr2 = new Thread(() => 
   { 
     for(int i=0; i<5; i++) 
       Console.Write("B"); 
   }); 
 Thread thr3 = new Thread(() => 
   { 
     for(int i=0; i<5; i++) 
       Console.Write("C"); 
   }); 
 thr1.Start(); 
 thr2.Start(); 
 thr1.Join(); 
 thr2.Join(); 
 thr3.Start(); 
  В общем случае порядок вывода первого и второго потоков не определен. Вывод третьего потока осуществляется только после завершения работы потоков thr1 и thr2.
Можно получить такие результаты:
    AAAAABBBBBCCCCC
    или
    BBBBBAAAAACCCCC
    Маловероятны, но возможны варианты
    ААВВАААВССССС
    или
    ААААВВВВВАССССС
    
                             