Будет ли это делать поток уровня ядра более предпочтительным, чем поток уровня пользователя, если системные вызовы так же быстры, как вызовы процедур? - PullRequest
0 голосов
/ 22 марта 2020

Некоторые результаты веб-поиска говорят мне, что единственный недостаток потока на уровне ядра - это медленная скорость его управления (создание, переключение, завершение и т. Д. c.). Кажется, что , если операция в потоке уровня ядра выполняется через системные вызовы, ответ на мой вопрос будет верным . Тем не менее, я много искал, чтобы выяснить, осуществляется ли управление потоком на уровне ядра через системный вызов, но ничего не нашел. И у меня всегда есть инстинкт, что такое управление должно осуществляться ОС автоматически, потому что только ОС знает, какой поток будет подходящим для запуска в определенное время c. Поэтому программистам кажется невозможным написать несколько явных системных вызовов для управления потоками. Я ценю любые идеи.

Ответы [ 2 ]

0 голосов
/ 22 марта 2020

Некоторые результаты веб-поиска говорят мне, что единственным недостатком потока на уровне ядра является медленная скорость его управления (создание, переключение, завершение и т. Д. c.).

Это не так просто. Чтобы понять, подумайте, что вызывает переключение задач. Вот (частичный) список:

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

  • достаточно времени прошло; либо вызывая переключение задач «отрезок времени», либо заставляя спящий поток разблокировать и выгрузить. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.

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

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

  • текущий запущенный поток попросил ядро ​​сделать что-то с Файл и ядро ​​получили «пропадание VFS-кеша», которое препятствует выполнению запроса без переключения задач. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.

  • текущий запущенный поток освобождает мьютекс или отправляет некоторые данные (например, с помощью трубы или розетки); заставляя поток, принадлежащий другому процессу, разблокировать и выгрузить. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.

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

  • создается новый поток для того же процесса; и новый поток вытесняет текущий запущенный поток. В этом случае вы запускаете код пользовательского пространства, когда обнаруживаете, что требуется переключение задач, поэтому переключение задач в пользовательском пространстве происходит быстрее; но только если ядро ​​не проинформировано (например, чтобы утилиты типа "top" могли правильно отображать детали для потоков) - если ядро ​​все равно проинформировано, тогда не имеет значения, где происходит переключение задач.

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

И у меня всегда есть инстинкт, что такое управление должно осуществляться ОС автоматически, потому что только ОС знает, какой поток будет подходящим для запуска в указанное время c.

Да; но возможно не по той причине, о которой вы думаете.

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

Другая проблема с многопоточностью в пользовательском пространстве заключается в том, что (для некоторых ЦП) - например, большинство ЦП 80x86) ЦП не являются независимыми, и при планировании могут приниматься решения об управлении питанием. Например; большинство 80x86 процессоров имеют гиперпоточность (где ядро ​​совместно используется 2 логическими процессорами), где умный планировщик может сказать: «один логический процессор в ядре работает с высоким приоритетом / важным потоком, поэтому другой логический процессор в том же ядре не должен запускать поток с низким приоритетом / неважным, потому что это замедлит выполнение важной работы "; большинство 80x86 процессоров имеют «турбо-буст» (с аналогичным «не позволяйте потокам с низким приоритетом разрушать возможности« турбо-буст / производительность потоков с высоким приоритетом »); и большинство процессоров имеют терморегулирование (где планировщик может сказать: «Эй, все эти потоки имеют низкий приоритет, поэтому давайте разгоним ЦП, чтобы он остыл и мог go быстрее (с большим запасом тепла), когда есть высокий приоритет / больше»). важная работа! ").

Будет ли это делать поток уровня ядра явно предпочтительным потоком уровня пользователя, если системные вызовы так же быстры, как вызовы процедур?

Если системные вызовы были такими же быстрыми, как и обычные вызовы процедур, тогда различия в производительности между потоками пользовательского пространства и ядром исчезли бы (но все другие проблемы с потоками пользовательского пространства остались бы). Однако причина, по которой системные вызовы медленнее, чем обычные вызовы процедур, заключается в том, что они проходят своего рода «барьер изоляции» (который изолирует код ядра и данные от вредоносного кода пользовательского пространства); поэтому, чтобы системные вызовы были такими же быстрыми, как и обычные вызовы процедур, вам нужно было бы избавиться от изоляции (фактически превратив ядро ​​в своего рода «глобальную общую библиотеку», которая может быть динамически связана), но без этой изоляции вы получите чрезвычайная катастрофа безопасности. Другими словами; чтобы иметь надежду на достижение приемлемой безопасности, системные вызовы должны быть медленнее, чем обычные вызовы процедур.

0 голосов
/ 22 марта 2020

Ваше основание c предпосылка неверна. Системные вызовы намного медленнее, чем вызовы процедур почти во всех интересных архитектурах.

Воспринимаемая пропускная способность процессора основана на конвейерной обработке, умозрительном выполнении и получении. Системный вызов останавливает конвейер, делает недействительным спекулятивное выполнение и останавливает спекулятивную выборку, является барьером для хранения и инструкций и может вызвать sh write fifo.

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

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

Другая стоимость системного вызова

Немного более 30 лет go, некоторые умные парни написали бумага о наименьших привилегиях. Концептуально это потрясающее зрелище. Основой c является то, что независимо от того, что делает ваша программа, она должна делать это с наименьшими возможными привилегиями.

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

Понятие user и kernel режимов выполнения возникло в ранних компьютерных системах и (за возможным исключением iax32 / 80286) все чаще показывают свою неадекватность в подключенной компьютерной среде. В какой-то момент вы могли бы сказать: «Это однопользовательская система»; но в IoT все стало многопользовательским.

Наименьшая привилегия настаивает на том, чтобы весь код выполнялся с минимальными привилегиями, необходимыми для выполнения поставленной задачи. Таким образом, в ядре не должно быть ничего, чего не должно быть. Если вы думаете, что это радикальная мысль, в статье Кена Томпсона о ядре UNIX, написанной в 1977 году, он точно так же заявляет.

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

...