Вятский государственный гуманитарный университет
Опубликован: 27.05.2013 | Доступ: свободный | Студентов: 2674 / 579 | Длительность: 09:18:00
Лекция 6:

Процессы и потоки

Аннотация: Основные понятия. Структуры данных для процессов и потоков. Создание процесса.

Основные понятия

Программа (program) – это последовательность команд, реализующая алгоритм решения задачи. Программа может быть записана на языке программирования (например, на Pascal, С++, BASIC); в этом случае она хранится на диске в виде текстового файла с расширением, соответствующим языку программирования (например, .PAS, .CPP, .VB). Также программа может быть представлена при помощи машинных команд; тогда она хранится на диске в виде двоичного исполняемого файла (executable file), чаще всего с расширением .EXE. Исполняемый файл генерируется из текста программы при компиляции.

Процесс (process) – это программа (пользовательская или системная) в ходе выполнения.

В современных операционных системах процесс представляет собой объект – структуру данных, содержащую информацию, необходимую для выполнения программы. Объект "Процесс" создается в момент запуска программы (например, пользователь дважды щелкает мышью на исполняемом файле) и уничтожается при завершении программы.

Если операционная система умеет запускать в одно и то же время несколько процессов, она называется многозадачной (multitasking) (пример – Windows), иначе – однозадачной (пример – MS DOS).

Процесс может содержать один или несколько потоков (thread) – объектов, которым операционная система предоставляет процессорное время. Сам по себе процесс не выполняется – выполняются его потоки. Таким образом, машинные команды, записанные в исполняемом файле, выполняются на процессоре в составе потока. Если потоков несколько, они могут выполняться одновременно.

Замечание. "Одновременное" (или "параллельное") выполнение потоков подразумевает одну из двух принципиально разных ситуаций, зависящих от количества процессоров (ядер) на компьютере. В том случае, если имеется всего один процессор с одним ядром, в один момент времени может выполняться только один поток. Однако операционная система может быстро переключать процессор с выполнения одного потока на другой и вследствие высокой частоты процессоров у пользователя возникает иллюзия одновременной работы нескольких программ. Такая ситуация называется псевдопараллельное выполнение потоков. Если в компьютере установлен многоядерный процессор или количество процессоров больше одного, то возможно истинно параллельное или просто параллельное выполнение потоков.

Операционные системы, поддерживающие несколько процессоров, называются многопроцессорными.

Если система допускает наличие нескольких потоков в одном процессе, она называется многопоточной (multithreading).

Многопоточность – это средство распараллеливания действий внутри процесса.

Примеры.

  1. В современных браузерах каждой вкладке соответствует свой поток.
  2. В текстовом редакторе один поток может управлять вводом текста, второй – проверять орфографию, третий – выводить документ на принтер.
  3. В компьютерной игре-стратегии за обработку действий каждого игрока отвечает отдельный поток.

Каждый процесс имеет свое собственное виртуальное адресное пространство (см. лекцию 11 "Управление памятью"), в котором независимо друг от друга работают все потоки процесса. Например, поток 1 может записывать данные в ячейку с адресом 100, а поток 2 читать данные из ячейки с адресом 101.

Замечание. Конечно, если два (или более) потоков захотят записать что-то свое в одну и ту же ячейку, возникнет неопределенность – кто раньше? Это одна из подзадач обширной проблемы синхронизации.

Каждый поток имеет свою область памяти – стек (stack), в которой хранятся, например, локальные переменные и параметры, передаваемые в функции. Кроме того, во время выполнения потока изменяются значения регистров процессора, которые при переключении на другой поток должны быть сохранены. Эта информация является частью контекста потока, поэтому при переключении потоков происходит переключение их контекстов (сохранение в память одного и загрузка другого).

Структуры данных для процессов и потоков

В WRK за управление процессами отвечает диспетчер процессов (base\ntos\ps), а многие важные структуры данных описаны в заголовочных файлах base\ntos\inc\ps.h и base\ntos\inc\ke.h.

Процесс в Windows описывается структурой данных EPROCESS [5]. Эта структура в WRK содержится в файле base\ntos\inc\ps.h (строка 238). Рассмотрим некоторые её поля.

  • Pcb (Process Control Block – блок управления процессом) – представляет собой структуру KPROCESS, хранящую данные, необходимые для планирования потоков, в том числе указатель на список потоков процесса (файл base\ntos\inc\ke.h, строка 944).
  • CreateTime и ExitTime – время создания и завершения процесса.
  • UniqueProcessId – уникальный идентификатор процесса.
  • ActiveProcessLinks – элемент двунаправленного списка (тип LIST_ENTRY), содержащего активные процессы.
  • QuotaUsage, QuotaPeak, CommitCharge – квоты (ограничения) на используемую память.
  • ObjectTable – таблица дескрипторов процесса.
  • Token – маркер доступа.
  • ImageFileName – имя исполняемого файла.
  • ThreadListHead – двунаправленный список потоков процесса.
  • Peb (Process Environment Block – блок переменных окружения процесса) – информация об образе исполняемого файла (файл public\sdk\inc\pebteb.h, строка 75).
  • PriorityClass – класс приоритета процесса (см. лекцию 9 "Планирование потоков").

Структура для потока в Windows называется ETHREAD и описывается в файле base\ntos\inc\ps.h (строка 545). Её основные поля следующие:

  • Tcb (Thread Control Block – блок управления потоком) – поле, которое является структурой типа KTHREAD (файл base\ntos\inc\ke.h, строка 1069) и необходимо для планирования потоков.
  • CreateTime и ExitTime – время создания и завершения потока.
  • Cid – структура типа CLIENT_ID, включающая два поля – идентификатор процесса-владельца данного потока и идентификатор самого потока.
  • ThreadsProcess – указатель на структуру EPROCESS процесса-владельца.
  • StartAddress – адрес системной стартовой функции потока. При создании потока сначала вызывается системная стартовая функция, которая запускает пользовательскую стартовую функцию.
  • Win32StartAddress – адрес пользовательской стартовой функции.

Создание процесса

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

Процесс, создавший другой процесс, называется родителем, а созданный процесс – потомком. Таким образом, формируется иерархия процессов.

Любой процесс начинает свою работу с основного (main), или первичного, потока, который может запускать (порождать) другие потоки – так образуется иерархия потоков.

В Windows для создания процессов применяется одна из следующих WinAPI-функций: CreateProcess, CreateProcessAsUser, CreateProcessWithTokenW, CreateProcessWithLogonW [10]. Далее при описании будем использовать функцию CreateProcess.

Создание процессов в Windows включает 7 этапов [5; 2].

1. Проверка и преобразование параметров.

Параметры функции CreateProcess проверяются на корректность и преобразуются к внутреннему формату системы.

2. Открытие исполняемого файла.

Происходит поиск файла, который содержит запускаемую программу. Обычно это файл с расширением .EXE, но могут быть также расширения .COM, .PIF, .BAT, .CMD. Определяется тип исполняемого файла:

  • Windows приложение (.EXE) – продолжается нормальное создание процесса;
  • приложение MS-DOS или Win16 (.EXE, .COM, .PIF) – запускается образ поддержки Ntvdm.exe;
  • командный файл (.BAT, .CMD) – запускается образ поддержки Cmd.exe;
  • приложение POSIX – запускается образ поддержки Posix.exe.

3. Создание объекта "Процесс".

Формируются структуры данных EPROCESS, KPROCESS, PEB, инициализируется адресное пространство процесса. Для этого вызывается системная функция NtCreateProcess (файл base\ntos\ps\create.c, строка 826), которая затем вызывает функцию NtCreateProcessEx (тот же файл, строка 884), а та, в свою очередь, функцию PspCreateProcess (тот же файл, строка 1016).

Замечание. Начиная с Windows Vista при создании процесса вызов нескольких функций (NtCreateProcess, NtWriteVirtualMemory, NtCreateThread) заменен вызовом одной функции NtCreateUserProcess.

Рассмотрим некоторые важные действия, выполняемые функцией PspCreateProcess.

  • Если в параметрах функции PspCreateProcess указан процесс-родитель:
    • по его дескриптору определяется указатель на объект EPROCESS (функция ObReferenceObjectByHandle, строка 1076);
    • наследуется от процесса родителя маска привязки к процессорам (Affinity, строка 1092).
  • Устанавливается минимальный и максимальный размеры рабочего набора (WorkingSetMinimum = 20 МБ и WorkingSetMaximum = 45 МБ, строки 1093 и 1094, см. лекцию 11 "Управление памятью").
  • Создается объект "Процесс" (структура EPROCESS) при помощи функции ObCreateObject (строка 1108).
  • Инициализируется двунаправленный список потоков при помощи функции InitializeListHead (строка 1134).
  • Копируется таблица дескрипторов родительского процесса (строка 1270).
  • Создается структура KPROCESS при помощи функции KeInitializeProcess (строка 1289).
  • Маркер доступа и другие данные, связанные с безопасностью (см. лекцию 13 "Безопасность", копируются из родительского процесса (функция PspInitializeProcessSecurity, строка 1302).
  • Устанавливается приоритет процесса, равный Normal; однако, если приоритет родительского процесса был Idle или Below Normal, то данный приоритет наследуется (строки 1307–1312, см. лекцию 9 "Планирование потоков").
  • Инициализируется адресное пространство процесса (строки 1337–1476).
  • Генерируется уникальный идентификатор процесса (функция ExCreateHandle) и сохраняется в поле UniqueProcessId структуры EPROCESS (строки 1482–1488).
  • Создается блок PEB и записывается в соответствующее поле структуры EPROCESS (строки 1550–1607).
  • Созданный объект вставляется в хвост двунаправленного списка всех процессов (строки 1613–1615) и в таблицу дескрипторов (строки 1639–1644). Первая вставка обеспечивает доступ к процессу по имени, вторая – по ID.
  • Определяется время создания процесса (функция KeQuerySystemTime) и записывается в поле CreateTime структуры EPROCESS (строка 1733).

4. Создание основного потока.

Формируется структура данных ETHREAD, стек и контекст потока, генерируется идентификатор потока. Поток создается при помощи функции NtCreateThread, определенной в файле base\ntos\ps\create.c, (строка 117), которая вызывает функцию PspCreateThread (тот же файл, строка 295). При этом выполняются следующие действия:

  • создается объект ETHREAD (строка 370).
  • Заполняются поля структуры ETHREAD, связанные с процессом-владельцем, – указатель на структуру EPROCESS (ThreadsProcess) и идентификатор процесса (Cid.UniqueProcess) (строки 396 и 398).
  • Генерируется уникальный идентификатор потока (функция ExCreateHandle) и сохраняется в поле Cid.UniqueThread структуры EPROCESS (строки 400–402).
  • Заполняются стартовые адреса потока, системный (StartAddress) и пользовательский (Win32StartAddress) (строки 468-476).
  • Инициализируются поля структуры KTHREAD при помощи вызова функции KeInitThread (строки 490–498 для потока пользовательского режима и 514–522 для потока режима ядра).
  • Функция KeStartThread заполняет остальные поля структуры ETHREAD и вставляет поток в список потоков процесса (строка 564).
  • Если при вызове функции PspCreateThread установлен флаг CreateSuspended ("Приостановлен") поток переводится в состояние ожидания (функция KeSuspendThread, строка 660); иначе вызывается функция KeReadyThread (строка 809), которая ставит поток в очередь готовых к выполнению потоков (см. лекцию 9 "Планирование потоков").

5. Уведомление подсистемы Windows.

Подсистеме Windows отправляется сообщение о вновь созданных процессе и его основном потоке, в которое входят их дескрипторы, идентификаторы и другая информация. Подсистема Windows добавляет новый процесс в общий список всех процессов и готовится к запуску основного потока.

6. Запуск основного потока.

Основной поток стартует, но начинают выполняться системные функции, завершающие создание процесса – осуществляется его инициализация.

7. Инициализация процесса.

  • Проверяется, не запущен ли процесс в отладочном режиме;
  • проверяется, следует ли производить предвыборку блоков памяти (тех участков памяти, которые при прошлом запуске использовались в течение первых 10 секунд работы процесса);
  • инициализируются необходимые компоненты и структуры данных процесса, например, диспетчер кучи;
  • загружаются динамически подключаемые библиотеки (DLL – Dynamic Link Library);
  • начинается выполнение стартовой функции потока.

Резюме

В этой лекции введены понятия "процесса" и "потока". Рассмотрены структуры данных, представляющие в операционной системе процесс (EPROCESS) и поток (ETHREAD). Описан ход создания процесса с использованием структур данных и функций Windows Research Kernel.

Следующая лекция посвящена алгоритмам планирования потоков и реализации этих алгоритмов в Windows.

Контрольные вопросы

  1. Приведите определение понятий "программа", "процесс", "поток", "стек".
  2. Опишите основные поля структуры EPROCESS.
  3. Какой структурой является поле Pcb структуры EPROCESS? Опишите поля этой структуры.
  4. Опишите основные поля структуры ETHREAD.
  5. Перечислите этапы создания процесса.
  6. Опишите этапы создания объекта "процесс".
  7. Опишите этапы создания основного потока.
Петр Кипа
Петр Кипа
Украина
Елизавета Бардо
Елизавета Бардо
Россия, Смоленская область