Fork vs Clone на 2.6 Kernel Linux


37

У мене є деяка плутанина щодо вилки та клону. Я бачив це:

  • fork - це для процесів, а клон - для ниток

  • fork просто викликає клон, клон використовується для всіх процесів і потоків

Чи одна з цих точних? У чому полягає відмінність цих двох системних дзвінків з ядром 2.6 Linux?

Відповіді:


52

fork()був оригінальним системним викликом UNIX. Його можна використовувати лише для створення нових процесів, а не для потоків. Також він портативний.

У Linux clone()- це новий універсальний системний виклик, який можна використовувати для створення нового потоку виконання. Залежно від прийнятих варіантів, новий потік виконання може дотримуватися семантики процесу UNIX, потоку POSIX, щось середнє або щось зовсім інше (наприклад, інший контейнер). Ви можете вказати всілякі параметри, що диктують, чи пам'ять, дескриптори файлів, різні простори імен, оброблячі сигналів тощо, отримати спільний доступ або скопіювати.

Оскільки clone()це системний виклик суперсети, реалізація fork()обгортки системних викликів у glibc насправді викликає clone(), але це детальна інформація про реалізацію, про яку програмістам не потрібно знати. Справжній реальний fork()системний виклик все ще існує в ядрі Linux з причин відсталої сумісності, хоча він і став надлишковим, оскільки програми, які використовують дуже старі версії libc або іншої libc, крім glibc, можуть використовувати його.

clone()також використовується для реалізації функції pthread_create()POSIX для створення потоків.

Портативні програми повинні дзвонити, fork()а pthread_create()не clone().


2
posix_spawn - ще одна відповідна функція - певна і менш портативна, ніж fork.
Випадково832

10

Здається, що clone()в Linux 2.6 плавають дві речі

Є системний виклик:

int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

Це "клон ()", описаний при виконанні 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 CPU):

20097 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b4ee9213770) = 20098
20097 exit_group(0)                     = ?
20098 exit_group(0)

У straceвиході не з'являється виклик "вилки" . clone()Виклик , який проявляється в straceвиході має дуже різні аргументи від людини-сторінки-клони. child_stack=0як перший аргумент відрізняється, ніж int (*fn)(void *).

Здається, що fork(2)системний виклик реалізований з точки зору реального clone() , подібно до того, як clone()реалізована "функція бібліотеки" . Реального clone() має інший набір аргументів від людини-сторінки-клони.

Простіше кажучи, обидва ваші, очевидно, суперечливі твердження про fork()та clone()є правильними. Хоча "клон" є різним.


9
"Це фактично функція бібліотеки, що розшаровується вгорі нижнього виклику системи 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().

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.