Некоторые результаты веб-поиска говорят мне, что единственным недостатком потока на уровне ядра является медленная скорость его управления (создание, переключение, завершение и т. Д. c.).
Это не так просто. Чтобы понять, подумайте, что вызывает переключение задач. Вот (частичный) список:
устройство сообщило драйверу устройства, что операция завершена (получены некоторые данные и т. Д. c), что вызвало поток, ожидающий разблокирования операции а затем выгрузить текущий запущенный поток. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.
достаточно времени прошло; либо вызывая переключение задач «отрезок времени», либо заставляя спящий поток разблокировать и выгрузить. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.
поток, обращающийся к виртуальной памяти, которая в данный момент недоступна запускает обработчик ошибок страницы ядра, который обнаруживает, что текущая задача должна ждать, пока ядро извлекает данные из пространства подкачки или из файла (если виртуальная память является частью файла отображения памяти), или должна ждать ядра освободить оперативную память, отправив другие страницы в пространство подкачки (если виртуальная память была задействована в «копировании при записи»); вызывая переключение задач, потому что текущая задача не может быть продолжена. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.
создается новый процесс и его начальный поток вытесняет текущий запущенный поток. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.
текущий запущенный поток попросил ядро сделать что-то с Файл и ядро получили «пропадание VFS-кеша», которое препятствует выполнению запроса без переключения задач. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.
текущий запущенный поток освобождает мьютекс или отправляет некоторые данные (например, с помощью трубы или розетки); заставляя поток, принадлежащий другому процессу, разблокировать и выгрузить. В этом случае вы запускаете код ядра, когда обнаруживаете, что переключение задач необходимо, поэтому переключение задач ядра происходит быстрее.
текущий запущенный поток освобождает мьютекс или отправляет некоторые данные (например, с помощью трубы или розетки); заставляя поток, принадлежащий тому же процессу, разблокировать и выгрузить. В этом случае вы запускаете код пользовательского пространства, когда обнаруживаете, что переключение задач необходимо, поэтому в теории переключение задач в пользовательском пространстве происходит быстрее, но на практике это также может быть индикатором плохого дизайна (использование слишком много потоков и / или слишком много конфликтов блокировок).
создается новый поток для того же процесса; и новый поток вытесняет текущий запущенный поток. В этом случае вы запускаете код пользовательского пространства, когда обнаруживаете, что требуется переключение задач, поэтому переключение задач в пользовательском пространстве происходит быстрее; но только если ядро не проинформировано (например, чтобы утилиты типа "top" могли правильно отображать детали для потоков) - если ядро все равно проинформировано, тогда не имеет значения, где происходит переключение задач.
Для большинства программ (которые не используют очень много потоков); выполнение задач переключается в ядре быстрее. Конечно, это также (надеюсь) довольно не имеет значения для производительности (потому что время, затрачиваемое на переключение задач, должно быть крошечным по сравнению с временем, потраченным на выполнение другой работы).
И у меня всегда есть инстинкт, что такое управление должно осуществляться ОС автоматически, потому что только ОС знает, какой поток будет подходящим для запуска в указанное время c.
Да; но возможно не по той причине, о которой вы думаете.
Другая проблема с многопоточностью в пользовательском пространстве (помимо замедления большинства переключений задач) заключается в том, что она не может поддерживать глобальные приоритеты потоков, не становясь серьезной угрозой безопасности. В частности, процесс не может знать, имеет ли его собственный поток более высокий или более низкий приоритет, чем поток, принадлежащий другому процессу (если только он не обладает информацией обо всех потоках для всей ОС, то есть информацией, которой не следует доверять обычным процессам) ; таким образом, многопоточность в пользовательском пространстве приводит к напрасной потере времени ЦП на выполнение неважной работы (для одного процесса), когда есть важная работа (для другого процесса).
Другая проблема с многопоточностью в пользовательском пространстве заключается в том, что (для некоторых ЦП) - например, большинство ЦП 80x86) ЦП не являются независимыми, и при планировании могут приниматься решения об управлении питанием. Например; большинство 80x86 процессоров имеют гиперпоточность (где ядро совместно используется 2 логическими процессорами), где умный планировщик может сказать: «один логический процессор в ядре работает с высоким приоритетом / важным потоком, поэтому другой логический процессор в том же ядре не должен запускать поток с низким приоритетом / неважным, потому что это замедлит выполнение важной работы "; большинство 80x86 процессоров имеют «турбо-буст» (с аналогичным «не позволяйте потокам с низким приоритетом разрушать возможности« турбо-буст / производительность потоков с высоким приоритетом »); и большинство процессоров имеют терморегулирование (где планировщик может сказать: «Эй, все эти потоки имеют низкий приоритет, поэтому давайте разгоним ЦП, чтобы он остыл и мог go быстрее (с большим запасом тепла), когда есть высокий приоритет / больше»). важная работа! ").
Будет ли это делать поток уровня ядра явно предпочтительным потоком уровня пользователя, если системные вызовы так же быстры, как вызовы процедур?
Если системные вызовы были такими же быстрыми, как и обычные вызовы процедур, тогда различия в производительности между потоками пользовательского пространства и ядром исчезли бы (но все другие проблемы с потоками пользовательского пространства остались бы). Однако причина, по которой системные вызовы медленнее, чем обычные вызовы процедур, заключается в том, что они проходят своего рода «барьер изоляции» (который изолирует код ядра и данные от вредоносного кода пользовательского пространства); поэтому, чтобы системные вызовы были такими же быстрыми, как и обычные вызовы процедур, вам нужно было бы избавиться от изоляции (фактически превратив ядро в своего рода «глобальную общую библиотеку», которая может быть динамически связана), но без этой изоляции вы получите чрезвычайная катастрофа безопасности. Другими словами; чтобы иметь надежду на достижение приемлемой безопасности, системные вызовы должны быть медленнее, чем обычные вызовы процедур.