Почему процессы лишены процессора для TOO долго, когда занят циклом в ядре Linux?

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

Я определил цикл занятости в моем модуле ядра Linux. В связи с этим другие процессы (например, sshd) не получают процессорное время для длинных промежутков времени (например, 20 секунд). Это понятно, так как у моей машины только один процессор и цикл занятости не дают возможности запланировать другие процессы.

Просто для эксперимента я добавил расписание() после каждой итерации в цикле занятости. Несмотря на это, это будет заставлять процессор занят, он должен позволить другим процессам работать, поскольку я звоню по расписанию(). Но, похоже, это не происходит. Мои процессы пользовательского уровня по-прежнему висят в течение длинных промежутков времени (20 секунд).

В этом случае поток ядра получил хорошее значение -5, а потоки уровня пользователя получили хорошее значение 0. Даже с низким приоритетом потока пользовательского уровня я думаю, что 20 секунд слишком длинны, чтобы не получить процессор.

Может кто-нибудь объяснить, почему это может произойти?

Примечание. Я знаю, как полностью удалить цикл занятости. Но я хочу понять поведение ядра здесь. Версия ядра - 2.6.18, а упреждение ядра отключено.

Ответ 1

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

Звучит так, как если бы ваш поток ядра делал очень мало работы в своем занятом цикле и вызывал schedule() каждый раз. Поэтому он, вероятно, не использует много процессорного времени и, следовательно, не имеет своего приоритета. Отрицательные приятные значения несут более тяжелый вес, чем положительные, поэтому разница между -5 и 0 довольно выражена. Комбинация этих двух эффектов означает, что я не слишком удивлен тем, что процессы пользовательского пространства пропускают.

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

Обратите внимание, что ваше ядро ​​(2.6.18) использует планировщик O (1), который существовал до тех пор, пока в 2.6 не был добавлен Полностью справедливый планировщик.23 (планировщик O (1) был добавлен в 2.6 для замены еще более раннего O (n) планировщик). CFS не использует очереди запуска и работает по-другому, поэтому вы можете увидеть другое поведение - я менее знаком с ним, поэтому я не хотел бы точно предсказать, какие различия вы увидите. Я достаточно убедился, что "совершенно справедливо" - это не тот термин, который я бы использовал на сильно загруженных SMP-системах с большим количеством ядер и процессов, но я также согласен с тем, что писать планировщик очень сложно и это далеко не самое худшее, что я видел, и у меня никогда не было существенной проблемы с ним на 4-8-ядерном настольном компьютере.