Шаги в переключении контекста
Меня просят описать этапы переключения контекста (1) между двумя разными процессами и (2) между двумя разными потоками в одном и том же процессе.
- Во время переключения контекста ядро сохранит контекст старого процесса на своей печатной плате, а затем загрузит сохраненный контекст нового процесса, запланированного для запуска.
- Операционная система может запланировать переключение контекста между двумя разными потоками в одном и том же процессе, чтобы они выполнялись параллельно, и поэтому обычно происходит быстрее, чем переключение контекста между двумя разными процессами.
Это слишком общее или что бы вы добавили, чтобы объяснить процесс более понятным?
3 ответа
Гораздо проще объяснить это в обратном порядке, потому что переключение процесса всегда включает переключение потока.
Типичное переключение контекста потока на одноядерном процессоре происходит следующим образом:
Все переключатели контекста инициируются "прерыванием". Это может быть фактическое аппаратное прерывание, которое запускает драйвер (например, от сетевой карты, клавиатуры, оборудования для управления памятью или таймера), или программный вызов (системный вызов), который выполняет последовательность вызовов, подобную аппаратному прерыванию. войти в ОС. В случае прерывания драйвера ОС предоставляет точку входа, которую может вызвать драйвер, вместо выполнения "нормального" прямого возврата прерывания и, таким образом, позволяет драйверу выходить через планировщик ОС, если ему требуется ОС для установки потока. готов (например, он дал сигнал семафору).
Нетривиальные системы должны будут инициировать изменение уровня защиты оборудования, чтобы войти в состояние ядра, чтобы можно было получить доступ к коду / данным ядра и т. Д.
Состояние ядра для прерванного потока должно быть сохранено. В простой встроенной системе это может быть просто помещение всех регистров в стек потоков и сохранение указателя стека в его блоке управления потоками (TCB).
На этом этапе многие системы переключаются на выделенный для ОС стек, чтобы основная часть требований к внутреннему стеку ОС не накладывалась на стек каждого потока.
Может потребоваться отметить положение стека потока, в котором произошло изменение состояния прерывания, для учета вложенных прерываний.
Драйвер / системный вызов выполняется и может изменить набор готовых потоков, добавив / удалив TCB из внутренних очередей для различных приоритетов потоков, например. Драйвер сетевой карты, возможно, установил событие или сигнализировал семафор, который ожидал другой поток, так что поток будет добавлен в готовый набор, или работающий поток мог вызвать sleep() и таким образом выбрать удалить себя из готового набора,
Алгоритм планировщика ОС запускается, чтобы решить, какой поток следует запустить следующим, обычно это готовый поток с наивысшим приоритетом, который находится в начале очереди для этого приоритета. Если следующий запускаемый поток принадлежит к другому процессу, отличному от ранее запущенного потока, здесь требуется дополнительная информация (см. Далее).
Сохраненный указатель стека из TCB для этого потока извлекается и загружается в указатель аппаратного стека.
Состояние ядра для выбранного потока восстанавливается. В моей простой системе регистры извлекаются из стека выбранного потока. Более сложные системы должны будут возвращаться к защите на уровне пользователя.
Выполняется возврат-прерывание, поэтому передача выполняется выбранному потоку.
В случае многоядерного процессора все сложнее. Планировщик может решить, что поток, который в данный момент выполняется на другом ядре, может быть необходимо остановить и заменить потоком, который только что стал готовым. Это можно сделать, используя межпроцессорный драйвер для аппаратного прерывания ядра, на котором запущен поток, который необходимо остановить. Сложность этой операции, помимо всего прочего, является хорошей причиной, чтобы не писать ядра ОС:)
Типичное переключение контекста процесса происходит следующим образом:
Переключение контекста процесса инициируется переключением контекста потока, поэтому все вышеперечисленное, 1-9, должно произойти.
На вышеприведенном шаге 5 планировщик решает запустить поток, принадлежащий другому процессу, который не принадлежал ранее запущенному потоку.
Аппаратные средства управления памятью должны быть загружены адресным пространством для нового процесса, то есть какими-либо селекторами / сегментами / флагами / всем, что позволяет потоку (-ам) нового процесса получать доступ к своей памяти.
Контекст любого оборудования FPU должен быть сохранен / восстановлен с печатной платы.
Может быть другое оборудование, предназначенное для процессов, которое необходимо сохранить / восстановить.
В любой реальной системе механизмы зависят от архитектуры, и вышеприведенное является грубым и неполным руководством к последствиям любого переключения контекста. Существуют и другие издержки, генерируемые переключателем процесса, которые не являются строго частью переключателя - после переключения процесса могут происходить дополнительные очистки кэша и сбои страниц, поскольку часть его памяти могла быть выгружена в пользу страниц, принадлежащих к процессу, владеющему потоком, который был запущен ранее.
Я надеюсь, что смогу предоставить более подробную / четкую картину.
Прежде всего, ОС планирует потоки, а не процессы, потому что потоки являются единственными исполняемыми модулями в системе. Переключатель процессов - это просто переключатель потоков, в котором потоки принадлежат разным процессам. В связи с этим в общем процедура переключения является обычной.
Планировщик должен быть вызван. Есть три основных сценария:
- Непроизвольное переключение. Произошло какое-то внешнее для вашего потока событие, которое повлияло на планирование. Например, таймер разбудил поток с высоким приоритетом, контроллер жесткого диска сообщил, что запрошенная часть файла была прочитана в память, и поток, ожидающий продолжения выполнения, системный таймер сообщил ядру, что ваш поток имел не хватило его кванта времени и т. д.
- Добровольное. Поток явно запрашивает перепланирование системным вызовом. Например, запросил выход, или запросил сон, или запросил ожидание освобождения мьютекса.
- Полудобровольный. Поток неявно инициировал перепланирование, выполняя некоторый несвязанный системный вызов. Например, он попросил систему прочитать файл. ОС перенаправила этот запрос на контроллер диска и, чтобы не тратить время на занятое ожидание результата, решила переключиться на другой поток.
Во всех случаях, чтобы иметь возможность выполнять переключение потоков, управление должно быть передано ядру. В случае непроизвольных переключений такой проход управления выполняется по прерыванию, в случае добровольного (и полу-добровольного) управления - через системный вызов.
В обоих случаях вход в ядро осуществляется с помощью процессора. Процессор выполняет проверку прав доступа, запоминает точку, в которой поток был прерван (чтобы иметь возможность возобновить его в будущем), переключается с пользовательской части стека потоков на его аналог ядра и передает управление предварительно определенной и хорошо известной точке в код ядра
- Первым действием, которое выполняет ядро, является сохранение содержимого регистров процессора, которое ядро будет использовать для своих собственных задач. Обычно ядро использует только регистры процессора общего назначения и сохраняет их, помещая в стек.
- Затем ядро обрабатывает первичный запрос - обрабатывает прерывание, или готовит запрос на чтение файла, или выполняет настройку таймера.
- В какой-то момент обработки запроса ядро выполняет действие, которое либо влияет на состояние текущего потока (решив, что в этом потоке ничего не нужно делать, и мы должны чего-то ждать), либо воздействует на состояние другого (их) потока (новых потоков) стала работоспособной в результате получения прерывания или из-за освобождения мьютекса и т. д.).
- Ядро вызывает диспетчер. Планировщик должен принять два решения. Первый вопрос о том, что делать с текущим потоком. Должен ли он быть заблокирован? Если так, в какую очередь ожидания это должно быть помещено? Если поток переключается непроизвольно, он помещается в конец очереди выполнения, если поток блокируется, потому что он ожидает чего-то меньшего, он помещается в один из очередей ожидания. Второе решение о том, какой поток следует запустить следующим.
- Как только оба решения приняты, scheduller выполняет переключение контекста, передавая ему два параметра - блок управления потоком текущего и следующего потоков.
- Сам переключатель контекста состоит из трех основных этапов. На первом этапе ядро выясняет, какие потоки регистров ЦП фактически используют, и сохраняет их содержимое либо в стеке, либо в TCB потока outgoint. Если поток не использует регистры FPU и SSE (например, для платформы IA-32), их содержимое не будет сохранено.
- Второй шаг - это сердце переключения контекста. Ядро выталкивает указатель текущей инструкции в стек, а значение указателя стека сохраняется в TCB исходящего потока. Затем он загружает в процессор новый указатель стека из TCB входящего потока и выскакивает указатель инструкции из его верхней части. Это! Новый активный стек означает новый активный поток. Начиная с этого момента, остальная часть системы будет думать, что она работает в контексте входящего потока.
- На третьем шаге ядро выясняет, какие регистры фактически используются входящим потоком, и загружает их ранее сохраненный контент (см. Шаг 1) обратно в ЦП.
- Затем ядро проверяет, принадлежат ли оба потока (входящий и исходящий) одному и тому же процессу или нет. Если они принадлежат к разным процессам (случай, который люди называют переключением процессов), ядро сбрасывает текущее адресное пространство, указывая MMU на новый набор таблиц преобразования виртуальных адресов в физические. В рамках этого процесса ЦП сбрасывает Translate Lookaside Buffer (TLB), который кэширует правила преобразования виртуальных адресов в физические. Новое виртуальное адресное пространство означает, что ранее кэшированные правила теперь неверны. Обратите внимание, что это единственный шаг во всем наборе действий переключения контекста, которые заботятся о процессах!
- Ядро подготавливает локальное хранилище потока для входящего потока. Например, сопоставление соответствующих страниц памяти с указанными адресами или, например, на IA-32 общий подход заключается в загрузке нового сегмента, который указывает на данные TLS входящего потока.
- Наконец, ядро загружается в адрес процессора части ядра входящего потока. После этого каждый новый вызов ядра будет использовать часть ядра входящего потока и не будет повреждать данные, хранящиеся в стеке исходящего потока.
- Еще один шаг, который может выполнить ядро, - перепрограммирование системного таймера. При этом ядро просит таймер позвонить и передать управление ядру через некоторое время. Этот период времени называется квантом времени потока.
- Наконец, ядрам нравится собирать статистику во время переключений контекста, включая информацию о том, сколько потоков процессорного времени потребляет, как переключение контекста происходит в системе в единицах реального времени, сколько раз были вызваны потоки, сколько раз они освобождали процессор добровольно и невольно, сколько раз они были исчерпаны, они квантовые. Часть этой статистики используется тогда планировщиком, который пытается принимать более оптимальные решения. Другая цель статистики - доставка системным администраторам и пользователям, чтобы показать им, что происходит под капотом системы.
- На этом этапе переключение потоков можно считать выполненным, и ядро продолжает прерванные ранее системные действия. Например, поток, который ожидал чтения файла, проверяет результат чтения в памяти и обрабатывает его. Или поток, заблокированный мьютексом в середине какой-то большой системной активности, продолжает эту деятельность.
- Наконец, позже или раньше поток завершает свою системную деятельность и хочет вернуться в пользовательский режим, чтобы продолжить свою основную задачу, для которой он первоначально использовался. В этот момент ядро извлекается из содержимого стека ядра регистров общего назначения, которое ранее было сохранено при входе в ядро, и просит ЦП выполнить возврат в пользовательский режим.
- CPU захватывает значения указателя инструкций и указателя стека, которые были ранее сохранены при входе в режим ядра, и восстанавливает их. Делая это, он также переключает поток обратно из части ядра своего стека в пользовательскую часть стека. Наконец, CPU сбрасывает разрешения кода, который будет выполняться, к более ограниченному набору (например, запрещает использование специальных системных инструкций или запрещает доступ к керел-коду и данным). Наконец ЦП передает управление обратно в точку, где поток был изначально прерван. В случае системного вызова поток будет продолжаться в той точке, где был вызван системный вызов, путем захвата и обработки его результата. В случае вытеснения прерыванием поток продолжит свое выполнение точно в той же точке, в которой он был, когда произошло прерывание. В этом случае он даже не узнает, что его прервали.
Некоторые краткие заметки:
- Ядро планирует и выполняет только потоки, а не процессы. Из-за этого контекста происходит перепутывание между потоками.
- Процедура переключения контекста между протекторами, принадлежащими разным процессам, по сути, такая же, как и между потоками, которые принадлежат одному и тому же процессу. В первом случае есть только один дополнительный шаг - загрузка нового виртуального адресного пространства (что приводит к сбросу TLB).
- Контекст потоков хранится либо в части ядра стека потока, либо в TCB потока (не в PCB!).
- Переключатель потоков вводит снижение производительности. Существует значительная прямая стоимость переключения потоков. И даже намного большие прямые затраты, вызванные загрязнением кэша и сбросом TLB (если виртуальное адресное пространство было перезагружено во время переключения).
- В коммутаторе состояние выполняемого в данный момент процесса должно быть каким-то образом сохранено, чтобы при его перепланировании это состояние можно было восстановить.
- Состояние процесса включает в себя все регистры, которые процесс может использовать, особенно счетчик программ, а также любые другие специфические данные операционной системы, которые могут быть необходимы. Обычно это хранится в структуре данных, называемой блоком управления процессом (PCB) или коммутационным блоком.
- Печатная плата может храниться в стеке отдельных процессов в памяти ядра (в отличие от стека вызовов пользовательского режима), или для этой информации может быть определенная структура данных, определенная операционной системой. Дескриптор PCB добавляется в очередь процессов, которые готовы к запуску, часто называемые готовой очередью.
- Поскольку операционная система фактически приостановила выполнение одного процесса, она может затем переключить контекст, выбрав процесс из очереди готовности и восстановив свою печатную плату. При этом счетчик программ с печатной платы загружается, и, таким образом, выполнение может продолжаться в выбранном процессе. Приоритет процесса и потока может влиять на то, какой процесс выбран из очереди готовности (т. Е. Это может быть очередь приоритета).
(Источник: переключение контекста)
1. Сохраните контекст процесса, который в данный момент выполняется на ЦП. Обновите блок управления процессом и другие важные поля.
2. переместите блок управления процессом вышеупомянутого процесса в соответствующую очередь, такую как очередь готовности, очередь ввода-вывода и т. Д.
3. Выберите новый процесс для выполнения.
4. Обновите блок управления процессом выбранного процесса. Это включает обновление состояния процесса до запущенного.
5. При необходимости обновите структуры данных управления памятью.
6. Восстановите контекст ранее запущенного процесса, когда он снова будет загружен в процессор. Это делается путем загрузки предыдущих значений блока управления процессом и регистров.