Наверх Системное программирование
Предыдущий раздел Оглавление Следующий раздел

3.4.4. Планирование потоков

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

Сначала рассмотрим потоки на уровне пользователя. Поскольку ядро о существовании потоков не знает, оно работает в обычном режиме, выбирая процесс, скажем, A, и передает процессу A управление до истечения его кванта времени. Планировщик потоков внутри процесса A решает, какой поток запустить, — скажем, A1. Из-за отсутствия таймерных прерываний для многозадачных потоков этот поток может продолжать работу, сколько ему понадобится. Если он полностью израсходует весь квант времени, отведенный процессу, ядро выберет для запуска другой процесс. Когда процесс A будет наконец-то снова запущен, поток A1 также возобновит работу. Он продолжит расходовать все отведенное процессу A время, 0 пока не закончит работу.

Теперь рассмотрим случай, когда потоки процесса A выполняют непродолжительную относительно доли выделенного процессорного времени работу, следовательно, каждый из них запускается на небольшой период времени, возвращая затем центральный процессор планировщику потоков. При этом, перед тем как ядро переключится на процесс B, может получиться следующая последовательность: A1, A2, A3, A1, A2, A3, A1, A2, A3, A1. Эта ситуация показана на рис. 3.14, а.

Рис

Рис. 3.14. Возможный вариант планирования потоков:
а — на уровне пользователя с квантом времени 50 мс и потоками,
работающими по 5 мс при работе центрального
процессора в пределах этого кванта; б —
на уровне ядра с теми же характеристиками

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

Теперь рассмотрим ситуацию с потоками, реализованными на уровне ядра. Здесь конкретный запускаемый поток выбирается ядром. Ему не нужно учитывать принадлежность этого потока конкретному процессу, но если понадобится, то он может это сделать. Потоку выделяется квант времени, по истечении которого его работа приостанавливается. Если выделен квант 50 мс, а запущен поток, который блокируется через 5 мс, то очередность потоков на период продолжительностью 30 мс может быть следующей: A1, B1, A2, B2, A3, B3, что невозможно получить при таких параметрах на пользовательском уровне. Эта ситуация частично показана на рис. 3.14, б.

Потоки на уровне пользователя и потоки на уровне ядра различаются в основном производительностью работы. Для переключения потоков, реализованных на уровне пользователя, требуется лишь небольшое количество машинных команд, а для потоков на уровне ядра требуется полное контекстное переключение, смена карты памяти и аннулирование кэша, что выполняется на несколько порядков медленнее. В то же время поток на уровне ядра, заблокированный на операции ввода-вывода, не вызывает приостановку всего процесса, как поток на уровне пользователя. Поскольку ядру известно, что на переключение с потока из процесса A на поток из процесса B затрачивается больше времени, чем на запуск второго потока из процесса A (из-за необходимости изменения карты памяти и обесценивания кэша памяти), то оно может учесть эти сведения при принятии решения. К примеру, если взять два равнозначных во всем остальном потока, один из которых принадлежит тому процессу, чей поток был только что заблокирован, а второй принадлежит другому процессу, предпочтение может быть отдано первому потоку.

Предыдущий раздел Оглавление Следующий раздел