Во время разработки библиотеки NPTL существенное внимание уделялось переписыванию планировщика ядра и проектированию такой модели многопоточности, которая бы позволила эффективно выполнять процессы, состоящие из тысяч отдельных потоков. Последующее тестирование показало, что данная цель была достигнута.
Реализация многопоточности вида M: N призвана совместить в себе преимущества моделей 1:1 и M:1 и в то же время устранить их недостатки.
В модели M: N каждый процесс может содержать несколько экземпляров KSE, к каждому из которых может быть привязано несколько потоков. Такая структура позволяет ядру распределять потоки приложения между процессорами, избавляясь от потенциальных проблем с масштабированием, которые присущи приложениям с большим количеством потоков.
Главным недостатком модели типа M: N является ее сложность. Задача планирования потоков ложится как на ядро, так и на библиотеку, работающую на уровне пользователя; эти две сущности должны взаимодействовать между собой и обмениваться информацией. Управление сигналами в соответствии с требованиями стандарта SUSv3 тоже является непростой задачей, если задейстовавать реализацию вида M: N.
Реализация вида M: N изначально рассматривалась в качестве основной для библиотеки NPTL, но была отклонена, так как требовала внесения слишком объемных и, вероятно, излишних изменений в ядро, особенно учитывая способность Linux хорошо масштабироваться при работе с большим количеством экземпляров KSE.
Linux предоставляет две основные реализации программного интерфейса Pthreads.
•
Некоторое время в качестве преемника библиотеки LinuxThreads рассматривали другую реализацию под названием NGPT (Next Generation POSIX Threads — POSIX-потоки следующего поколения), разработанную в компании IBM. Библиотека NGPT использовала модель M: N и демонстрировала существенный прирост в производительности по сравнению с LinuxThreads. Однако разработчики NPTL решили заняться новой реализацией. И это решение себя оправдало, так как модель вида 1:1, на которой основана библиотека NPTL, показывала лучшие результаты, чем NGPT. С выпуском NPTL разработка проекта NGPT была прекращена.
В следующих разделах мы подробно рассмотрим эти две реализации и выделим аспекты, в которых они расходятся с требованиями стандарта SUSv3 для спецификации Pthreads.
На данном этапе стоит отметить, что библиотека LinuxThreads уже считается устаревшей; она не поддерживается в glibc версии 2.4 и выше. Все нововведения, касающиеся потоков, добавляются в библиотеку NPTL.
33.5.1. LinuxThreads
На протяжении многих лет библиотека LinuxThreads была основной реализацией многопоточности в Linux, и ее хватало для написания различных многопоточных приложений. Ниже перечислены ее главные особенности.
• Потоки создаются с помощью вызова clone(), для которого указываются следующие флаги:
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_SIGHAND
• Это означает, что потоки в LinuxThreads разделяют виртуальную память, файловые дескрипторы, атрибуты файловой системы (umask, корневой и текущий каталог) и действия сигналов. При этом идентификаторы текущего и родительского процессов не разделяются.
• Помимо потоков, создаваемых самим приложением, LinuxThreads создает дополнительный «управляющий» поток, который отвечает за создание и завершение потоков.
• Внутренняя работа LinuxThreads основана на сигналах. Если ядро поддерживает сигналы реального времени (Linux 2.2 и выше), эта библиотека использует первые три из них. В более старых ядрах применяются сигналы SIGUSR1 и SIGUSR2. Сигналы этого вида недоступны на уровне приложения (такой подход приводит к значительным задержкам при выполнении различных операций синхронизации потоков).
Расхождения библиотеки LinuxThreads со спецификацией
LinuxThreads не соответствует спецификации Pthreads из стандарта SUSv3 в целом ряде аспектов (реализация LinuxThreads была ограничена возможностями ядра, доступными на момент ее разработки; она была совместима настолько, насколько это было возможно в тех условиях). Расхождения со спецификацией перечислены в следующем списке.