fork()был оригинальный системный вызов UNIX. Он может использоваться только для создания новых процессов, а не потоков. Кроме того, это портативный.
В Linux clone()это новый, универсальный системный вызов, который можно использовать для создания нового потока выполнения. В зависимости от переданных параметров новый поток выполнения может придерживаться семантики процесса UNIX, потока POSIX, чего-то промежуточного или чего-то совершенно другого (например, другого контейнера). Вы можете указать все виды опций, определяющих, будут ли совместно использоваться или копироваться память, файловые дескрипторы, различные пространства имен, обработчики сигналов и т. Д.
Поскольку clone()это системный вызов superset, реализация fork()оболочки системных вызовов в glibc фактически вызывает clone(), но это деталь реализации, о которой программистам не нужно знать. Реальный реальный fork()системный вызов все еще существует в ядре Linux по причинам обратной совместимости, даже если он стал избыточным, потому что программы, которые используют очень старые версии libc, или другой libc, кроме glibc, могут использовать его.
clone()также используется для реализации pthread_create()функции POSIX для создания потоков.
Портативные программы должны звонить, fork()а pthread_create()не clone().
Это «clone ()», описанный при выполнении man 2 clone.
Если вы прочитаете эту справочную страницу достаточно близко, вы увидите это:
It is actually a library function layered on top of the
underlying clone() system call.
По-видимому, вы должны реализовать многопоточность, используя «библиотечную функцию», наложенную на системно вызывающий вызов с однозначным названием.
Я написал короткую программу:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int
main(int ac, char **av)
{
pid_t cpid;
switch (cpid = fork()) {
case 0: // Child process
break;
case -1: // Error
break;
default: // parent process
break;
}
return 0;
}
Скомпилировал его с помощью:, c99 -Wall -Wextraи запустил, strace -fчтобы увидеть, что на самом деле делают системные вызовы разветвления. Я получил это straceна машине Linux 2.6.18 (процессор x86_64):
В straceвыводе не появляется вызов "fork" . clone()Вызов , который проявляется в straceвыходе имеет очень разные аргументы от человека-страницы-клона. child_stack=0как первый аргумент отличается от int (*fn)(void *).
Похоже, что fork(2)системный вызов реализован в терминах реальногоclone() , точно так же, как clone()реализована «библиотечная функция» . Реальногоclone() имеет другой набор аргументов от человека-страницы-клона.
Проще говоря, оба ваших кажущихся противоречивыми высказывания о fork()и clone()являются правильными. Вовлеченный «клон» отличается, однако.
«На самом деле это библиотечная функция, расположенная поверх основного системного вызова clone ()». - в общем, это относится к каждому системному вызову. Программисты фактически всегда вызывают функции в libc, которые названы в честь системного вызова. Это связано с тем, что для выполнения реального реального системного вызова непосредственно из C требуется магия, зависящая от платформы (обычно путем принудительной установки некоторой ловушки ЦП, зависит от архитектуры ABI) и машинный код, который лучше всего оставить делегированным в libc.
Селада
1
@Celada - да, согласился. Просто это man 2 cloneформулирует это именно так, что, как мне показалось, запутало проблему и помешало спрашивающему получить хороший ответ.
Брюс Эдигер
2
Я считаю , что средства Manpage , чтобы указать , что список аргументов из cloneбиблиотеки функций существенно отличается от списка аргументов , принятого базовой системы вызова. В частности, системный вызов всегда возвращается дважды в одном стеке, как это forkделает традиционный ; все аргументы, относящиеся к дочернему стеку, обрабатываются строго в пространстве пользователя. Смотрите, например, sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…
zwol
1
Я хотел дать ваш ответ лучший ответ, потому что он качается, но стадо меня поразило и пошло с первым ответом. Она получает очки за время отклика. Спасибо за ваше объяснение.
Грегг Левенталь
6
fork()это просто определенный набор флагов для системного вызова clone(). clone()достаточно общего, чтобы создать «процесс» или «поток», или даже странные вещи, которые находятся где-то между процессами и потоками (например, разные «процессы», которые совместно используют одну и ту же таблицу дескрипторов файлов).
По сути, для каждого «типа» информации, связанной с контекстом выполнения в ядре, clone()вы можете выбрать псевдоним этой информации или ее копирование. Потоки соответствуют псевдонимам, процессы соответствуют копированию. Указывая промежуточные комбинации флагов для clone(), вы можете создавать странные вещи, которые не являются потоками или процессами. Обычно вы не должны этого делать, и я полагаю, что во время разработки ядра Linux возникли споры о том, должен ли он предусматривать такой общий механизм, как clone().
Похоже,
clone()
в Linux 2.6 есть две вещиЕсть системный вызов:
Это «clone ()», описанный при выполнении
man 2 clone
.Если вы прочитаете эту справочную страницу достаточно близко, вы увидите это:
По-видимому, вы должны реализовать многопоточность, используя «библиотечную функцию», наложенную на системно вызывающий вызов с однозначным названием.
Я написал короткую программу:
Скомпилировал его с помощью:,
c99 -Wall -Wextra
и запустил,strace -f
чтобы увидеть, что на самом деле делают системные вызовы разветвления. Я получил этоstrace
на машине Linux 2.6.18 (процессор x86_64):В
strace
выводе не появляется вызов "fork" .clone()
Вызов , который проявляется вstrace
выходе имеет очень разные аргументы от человека-страницы-клона.child_stack=0
как первый аргумент отличается отint (*fn)(void *)
.Похоже, что
fork(2)
системный вызов реализован в терминах реальногоclone()
, точно так же, какclone()
реализована «библиотечная функция» . Реальногоclone()
имеет другой набор аргументов от человека-страницы-клона.Проще говоря, оба ваших кажущихся противоречивыми высказывания о
fork()
иclone()
являются правильными. Вовлеченный «клон» отличается, однако.источник
man 2 clone
формулирует это именно так, что, как мне показалось, запутало проблему и помешало спрашивающему получить хороший ответ.clone
библиотеки функций существенно отличается от списка аргументов , принятого базовой системы вызова. В частности, системный вызов всегда возвращается дважды в одном стеке, как этоfork
делает традиционный ; все аргументы, относящиеся к дочернему стеку, обрабатываются строго в пространстве пользователя. Смотрите, например, sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…fork()
это просто определенный набор флагов для системного вызоваclone()
.clone()
достаточно общего, чтобы создать «процесс» или «поток», или даже странные вещи, которые находятся где-то между процессами и потоками (например, разные «процессы», которые совместно используют одну и ту же таблицу дескрипторов файлов).По сути, для каждого «типа» информации, связанной с контекстом выполнения в ядре,
clone()
вы можете выбрать псевдоним этой информации или ее копирование. Потоки соответствуют псевдонимам, процессы соответствуют копированию. Указывая промежуточные комбинации флагов дляclone()
, вы можете создавать странные вещи, которые не являются потоками или процессами. Обычно вы не должны этого делать, и я полагаю, что во время разработки ядра Linux возникли споры о том, должен ли он предусматривать такой общий механизм, какclone()
.источник