Переключение контекста

Эта статья находится на начальном уровне проработки, в одной из её версий выборочно используется текст из источника, распространяемого под свободной лицензией
Материал из энциклопедии Руниверсалис

Переключение контекста (англ. context switch) — в многозадачных ОС и средах — процесс прекращения выполнения процессором одной задачи (процесса, потока, нити) с сохранением всей необходимой информации и состояния, необходимых для последующего продолжения с прерванного места, и восстановления и загрузки состояния задачи, к выполнению которой переходит процессор.

В процедуру переключения контекста входит так называемое планирование задачи — процесс принятия решения, какой задаче передать управление.

Описание

При переключении контекста происходит сохранение и восстановление следующей информации:

  • Регистровый контекст регистров общего назначения (в том числе флаговый регистр)
  • Контекст состояния сопроцессора с плавающей точкой / регистров MMX (x86)
  • Состояние регистров SSE, AVX (x86)
  • Состояние сегментных регистров (x86)
  • Состояние некоторых управляющих регистров (например, регистр CR3, отвечающий за страничное отображение памяти процесса) (x86)

В ядре ОС с каждым потоком связаны следующие структуры:

  • Общая информация pid, tid, uid, gid, euid, egid и т. д.
  • Состояние процесса/потока
  • Права доступа
  • Используемые потоком ресурсы и блокировки
  • Счетчики использования ресурсов (например, таймеры использованного процессорного времени)
  • Регионы памяти, выделенные процессу

Переключение контекста и производительность

Кроме того, что очень важно, при переключении контекста происходят следующие программно-незаметные аппаратные действия, влияющие на производительность:

  • Происходит очистка конвейера команд и данных процессора
  • Очищается TLB, отвечающий за страничное отображение линейных адресов на физические.

Кроме того, следует учесть следующие факты, влияющие на состояние системы:

  • Содержимое кэша (особенно это касается кэша первого уровня), накопленное и «оптимизированное» под выполнение одного потока, оказывается совершенно неприменимым к новому потоку, на который происходит переключение.
  • При переключении контекста на процесс, который до этого долгое время не использовался (см. Подкачка страниц), многие страницы могут физически отсутствовать в оперативной памяти, что порождает подгрузку вытесненных страниц из вторичной памяти.

Переключение контекста и ОС

С точки зрения прикладного уровня переключение контекста можно разделить на добровольное (voluntary) и принудительное (non-voluntary): выполняющийся процесс/поток может сам передать управление другому потоку либо ядро может насильно отобрать у него управление.

  1. Ядро ОС может отобрать управление у выполняющегося процесса/потока при истечении кванта времени, выделенного на выполнение. С точки зрения программиста это означает, что управление могло уйти от потока в «самый неподходящий» момент времени, когда структуры данных могут находиться в противоречивом состоянии из-за того, что их изменение не было завершено.
  2. Выполнение блокирующего системного вызова. Когда приложение производит ввод-вывод, ядро может решить, что можно отдать управление другому потоку/процессу в ожидании, пока запрошенный данным потоком дисковый либо сетевой ввод-вывод будет выполнен. Данный вариант является самым производительным.
  3. Синхронизирующие примитивы ядра. Мьютексы, семафоры и т. д. Это и есть основной источник проблем с производительностью. Недостаточно продуманная работа с синхронизирующими примитивами может приводить к десяткам тысяч, а в особо запущенных случаях — и к сотням тысяч переключений контекста в секунду. [источник не указан 3749 дней]
  4. Системный вызов, явно ожидающий наступления события (select, poll, epoll, pause, wait, …) либо момента времени (sleep, nanosleep, …). Данный вариант является относительно производительным, так как ядро ОС имеет информацию об ожидающих процессах.

Особенности процедуры планировщика

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

Реализации переключения контекста в современных ОС

Как видно из вышесказанного, переключение контекста является очень ресурсоёмкой операцией, причем, чем более «навороченым» является процессор, тем более ресурсоёмкой эта операция становится. Исходя из этого, ядро использует ряд стратегий, чтобы, во-первых, сократить количество переключений контекста, а во вторых, сделать переключение контекста менее ресурсоёмким.

Методы уменьшения количества переключений контекста:

  • Существует возможность конфигурирования выделяемого потоку кванта процессорного времени. При сборке ядра Linux возможно указать Server/Desktop/Low-Latency Desktop. Для серверных конфигураций этот квант больше.

Методы снижения ресурсоемкости переключения контекста:

  • При переключении контекста между потоками, разделяющими одно адресное пространство в пределах одного процесса, ядро не трогает регистр CR3, тем самым сохраняя TLB
  • Во многих случаях ядро располагается в том же адресном пространстве, что и пользовательский процесс. При переключении контекста между user-space и kernel-space (и обратно), что, например, происходит при выполнении системных вызовов, ядро не трогает регистр CR3, тем самым сохраняя TLB
  • Производя планирование, ядро старается минимизировать перемещение процесса между вычислительными ядрами в SMP-системе, тем самым улучшая эффективность работы кэша второго уровня.
  • Реальное сохранение/восстановление контекста регистров сопроцессора плавающей точки и MMX/SSE-контекста происходит при первом обращении нового потока, что оптимизировано под случай, когда большинство потоков производит только операции с регистрами общего назначения.

Вышеприведенные примеры относятся к ядру Linux, однако прочие операционные системы так же применяют сходные методы, хотя в случае проприетарных ОС доказать/опровергнуть использование этого является проблематичным.

Замечания о терминологии

Ссылки