Я просматриваю эту книгу « Расширенное программирование для Linux» Марка Митчелла, Джеффри Олдхэма и Алекса Самуэля. Это с 2001 года, так что немного стар. Но я все равно нахожу это довольно хорошим.
Однако я дошел до того, что он отличается от того, что мой Linux выдает в выводе оболочки. На странице 92 (116 в средстве просмотра) глава 4.5 Реализация потоков GNU / Linux начинается с абзаца, содержащего это утверждение:
Реализация потоков POSIX в GNU / Linux существенно отличается от реализации потоков во многих других UNIX-подобных системах: в GNU / Linux потоки реализуются как процессы.
Это кажется ключевым моментом и позже проиллюстрировано кодом Си. Вывод в книге:
main thread pid is 14608
child thread pid is 14610
И в моем Ubuntu 16.04 это:
main thread pid is 3615
child thread pid is 3615
ps
выход поддерживает это.
Я думаю, что-то должно было измениться между 2001 и сейчас.
Следующий подраздел на следующей странице, 4.5.1 Обработка сигналов, основан на предыдущем утверждении:
Поведение взаимодействия между сигналами и потоками варьируется от одной UNIX-подобной системы к другой. В GNU / Linux поведение диктуется тем фактом, что потоки реализованы как процессы.
И, похоже, это будет еще важнее позже в книге. Может ли кто-нибудь объяснить, что здесь происходит?
Я видел это. Являются ли потоки ядра Linux действительно процессами ядра? , но это не очень помогает. Я не совсем понимаю.
Это код C:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* thread_function (void* arg)
{
fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
/* Spin forever. */
while (1);
return NULL;
}
int main ()
{
pthread_t thread;
fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
pthread_create (&thread, NULL, &thread_function, NULL);
/* Spin forever. */
while (1);
return 0;
}
getpid
возвращают так называемый идентификатор группы потоков и получают уникальный идентификатор для процесса, который вам нужно использоватьgettid
. Однако, кроме ядра, большинство людей и инструментов будут вызывать поток, группирующий процесс, и вызывать процесс потоком для согласованности с другими системами.Ответы:
Я думаю, что эта часть
clone(2)
справочной страницы может прояснить разницу. PID:Фраза "потоки реализованы как процессы" относится к вопросу о потоках, которые в прошлом имели отдельные идентификаторы PID. По сути, в Linux изначально не было потоков внутри процесса, а были отдельные процессы (с отдельными идентификаторами PID), которые могли иметь некоторые общие ресурсы, такие как виртуальная память или файловые дескрипторы.
CLONE_THREAD
и разделение идентификатора процесса (*) и идентификатора потока делает поведение Linux более похожим на другие системы и в этом смысле больше похожим на требования POSIX. Хотя технически ОС все еще не имеет отдельных реализаций для потоков и процессов.Обработка сигналов была еще одной проблемной областью со старой реализацией, это более подробно описано в статье, на которую @FooF ссылается в своем ответе .
Как отмечается в комментариях, Linux 2.4 также был выпущен в 2001 году, в том же году, что и книга, так что неудивительно, что новости не попали в эту печать.
источник
Вы правы, действительно "что-то должно было измениться между 2001 и сейчас". Книга, которую вы читаете, описывает мир в соответствии с первой исторической реализацией потоков POSIX в Linux, названной LinuxThreads (см. Также статью в Википедии ).
У LinuxThreads были некоторые проблемы совместимости со стандартом POSIX - например, потоки, не разделяющие PID, - и некоторые другие серьезные проблемы. Чтобы исправить эти недостатки, Red Hat инициировала другую реализацию под названием NPTL (Native POSIX Thread Library), чтобы добавить необходимую поддержку ядра и библиотеки пользовательского пространства для достижения лучшего соответствия POSIX (взяв хорошие части из еще одного конкурирующего проекта IBM по повторной реализации под названием NGPT (" Последующие потоки Posix "), см. Статью в Википедии об NPTL ). Дополнительные флаги, добавленные к
clone(2)
системному вызову (особенноCLONE_THREAD
это@ikkkachu
указывает в его ответе ), вероятно, являются наиболее очевидной частью модификаций ядра. Часть работы в пользовательском пространстве была в конечном итоге включена в библиотеку GNU C.Тем не менее, в настоящее время некоторые встроенные Linux SDK используют старую реализацию LinuxThreads, поскольку они используют уменьшенную версию LibC, занимающую меньший объем памяти, называемую uClibc (также называемую µClibc) , и потребовалось немало лет, прежде чем реализация пространства пользователя NPTL из GNU LibC была портирована и принята за реализация потоков POSIX по умолчанию, как правило, эти специальные платформы не стремятся с молниеносной скоростью следовать новейшим модам. Это можно заметить, заметив, что действительно PID для разных потоков на этих платформах также отличаются в отличие от спецификаций стандарта POSIX - точно так же, как и в книге, которую вы читаете. На самом деле, как только вы позвонили
pthread_create()
Вы неожиданно увеличили количество процессов с одного до трех, так как для сохранения беспорядка потребовался дополнительный процесс.Страница руководства Linux pthreads (7) содержит всесторонний и интересный обзор различий между ними. Другое поучительное, хотя и устаревшее описание различий - это статья Ульриха Деппера и Инго Молнара о разработке NPTL.
Я рекомендую вам не относиться к этой части книги слишком серьезно. Вместо этого я рекомендую Butenhof's Programming потоки POSIX и справочные страницы POSIX и Linux по этому вопросу. Многие учебники по этому вопросу неточны.
источник
Потоки (пользовательского пространства) не реализованы как процессы как таковые в Linux, так как у них нет собственного частного адресного пространства, они все еще совместно используют адресное пространство родительского процесса.
Однако эти потоки реализованы так, чтобы использовать систему учета процессов ядра, поэтому им присваивается собственный идентификатор потока (TID), но им присваиваются тот же PID и «идентификатор группы потоков» (TGID), что и у родительского процесса - это в отличие от форк, где создаются новые TGID и PID, и TID такой же, как PID.
Таким образом, кажется, что последние ядра имели отдельный TID, который можно запрашивать, это то, что отличается для потоков, подходящий фрагмент кода, чтобы показать это в каждом из main () thread_function () выше:
Таким образом, весь код с этим будет:
Дать пример вывода:
источник
По сути, информация в вашей книге исторически точна из-за позорно плохой истории реализации потоков в Linux. Этот мой ответ на связанный вопрос о SO также служит ответом на ваш вопрос:
https://stackoverflow.com/questions/9154671/distinction-between-processes-and-threads-in-linux/9154725#9154725
источник
Внутренне в ядре linux не существует таких процессов или потоков. Процессы и потоки являются в основном концепцией пользовательского пространства, само ядро видит только «задачи», которые являются планируемым объектом, который не может совместно использовать ни один, некоторые или все свои ресурсы с другими задачами. Потоки - это задачи, которые были настроены для совместного использования большей части своих ресурсов (адресного пространства, mmaps, каналов, обработчиков открытых файлов, сокетов и т. Д.) С родительской задачей, а процессы - это задачи, которые были настроены для совместного использования минимальных ресурсов с родительской задачей. ,
Когда вы используете API-интерфейс Linux напрямую ( clone () , а не fork () и pthread_create () ), у вас гораздо больше гибкости в определении того, сколько ресурсов совместно использовать или нет, и вы можете создавать задачи, которые не являются полностью процесс, ни полностью поток. Если вы используете эти низкоуровневые вызовы напрямую, также можно создать задачу с новым TGID (таким образом, большинство инструментов пользователя обрабатывают его как процесс), который фактически разделяет все свои ресурсы с родительской задачей, или наоборот, для создания задача с общим TGID (таким образом большинство инструментов пользователя обрабатывают его как поток), который не разделяет ресурс со своей родительской задачей.
В то время как Linux 2.4 реализует TGID, это в основном только для учета ресурсов. Многие пользователи и инструмент пространства пользователей считают полезным иметь возможность группировать связанные задачи вместе и сообщать об использовании их ресурсов вместе.
Реализация задач в Linux намного более гибкая, чем мировоззрение процессов и потоков, представленное инструментами пользовательского пространства.
источник
В 1996 году Линус Торвальдс заявил в списке рассылки ядра, что «и потоки, и процессы рассматриваются как« контекст выполнения »», то есть «просто конгломерат всего состояния этого CoE… включает такие вещи, как CPU состояние, состояние MMU, разрешения и различные состояния связи (открытые файлы, обработчики сигналов и т. д.) ".
Как вы можете видеть, эта программа порождает 25 потоков одновременно, каждый из которых будет спать 100 секунд, а затем снова присоединится к основной программе. После того, как все 25 потоков присоединились к программе, программа завершается и завершает работу.
Используя
top
вы сможете увидеть 25 экземпляров программы "threads2". Но почка скучная. Выводps auwx
еще менее интересен ... НОps -eLf
становится довольно захватывающим.Вы можете увидеть здесь все 26 CoEs, которые
thread2
создала программа. Все они имеют один и тот же идентификатор процесса (PID) и идентификатор родительского процесса (PPID), но каждый из них имеет свой идентификатор LWP (легкий процесс), а количество LWP (NLWP) указывает на то, что существует 26 CoE - основная программа и 25 потоков, созданных им.источник
Когда дело касается Linux, процессы и потоки - это одно и то же. Который должен сказать , что они создаются с помощью той же системы вызова:
clone
.Если вы подумаете об этом, разница между потоками и процессами заключается в том, какие объекты ядра будут совместно использоваться дочерним и родительским объектами. Для процессов это не так уж много: открытые файловые дескрипторы, сегменты памяти, в которые еще не было записано, возможно, несколько других, о которых я не могу вспомнить. Для потоков доступно гораздо больше объектов, но не для всех.
Что делает потоки и объекты ближе в Linux, так это
unshare
системный вызов. Объекты ядра, которые начинаются как общие, могут не быть разделены после создания потока. Таким образом, вы можете, например, иметь два потока одного и того же процесса, которые имеют разное пространство файловых дескрипторов (отменив совместное использование файловых дескрипторов после создания потоков). Вы можете проверить это самостоятельно, создав поток, вызвавunshare
оба потока, а затем закрыв все файлы и открыв новые файлы, каналы или объекты в обоих потоках. Затем загляните внутрь,/proc/your_proc_fd/task/*/fd
и вы увидите, что у каждогоtask
(который вы создали как поток) будут разные fd.Фактически, как создание новых потоков, так и новых процессов являются библиотечными процедурами, которые вызывают
clone
нижележащие объекты и указывают, какой из объектов ядра вновь созданный процесс-поток-штуковина (то естьtask
) поделится с вызывающим процессом / потоком.источник