fork()était l'appel système UNIX d'origine. Il ne peut être utilisé que pour créer de nouveaux processus, pas de threads. En outre, il est portable.
Sous Linux, clone()un nouvel appel système polyvalent peut être utilisé pour créer un nouveau thread d’exécution. En fonction des options passées, le nouveau thread d'exécution peut adhérer à la sémantique d'un processus UNIX, d'un thread POSIX, d'un élément intermédiaire ou de quelque chose de complètement différent (comme un conteneur différent). Vous pouvez spécifier toutes sortes d'options pour déterminer si la mémoire, les descripteurs de fichier, les différents espaces de noms, les gestionnaires de signaux, etc. sont partagés ou copiés.
Puisque clone()est l'appel système superset, l'implémentation du fork()wrapper d'appel système dans glibc appelle en réalité clone(), mais il s'agit d'un détail d'implémentation que les programmeurs n'ont pas besoin de connaître. L' fork()appel système réel existe toujours dans le noyau Linux pour des raisons de compatibilité ascendante, même s'il est devenu redondant, car les programmes qui utilisent des versions très anciennes de libc, ou une autre libc que glibc, pourraient l'utiliser.
clone()est également utilisé pour implémenter la pthread_create()fonction POSIX pour la création de threads.
Les programmes portables doivent appeler fork()et pthread_create()non clone().
C'est le "clone ()" décrit en faisant man 2 clone.
Si vous lisez suffisamment cette page de manuel, vous verrez ceci:
It is actually a library function layered on top of the
underlying clone() system call.
Apparemment, vous êtes censé implémenter le threading en utilisant la "fonction de bibliothèque" superposée à l'appel système qui porte un nom identique.
J'ai écrit un programme court:
#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;
}
Compilez-le avec: c99 -Wall -Wextraet parcourez-le strace -fpour voir ce que font réellement les appels système faisant appel à la fourchette. Je l'ai obtenu stracesur une machine Linux 2.6.18 (CPU x86_64):
Aucun appel "fork" n'apparaît dans la stracesortie. L' clone()appel qui apparaît dans la stracesortie a des arguments très différents de ceux du clone man-page. child_stack=0comme le premier argument est différent de int (*fn)(void *).
Il semble que l' fork(2)appel système soit implémenté en termes réelsclone() , tout comme la "fonction de bibliothèque" clone()est implémentée. Le réelclone() a un ensemble d'arguments différent du clone man-page.
De manière simpliste, vos deux déclarations apparemment contradictoires à propos de fork()et clone()sont correctes. Le "clone" impliqué est différent, cependant.
"C’est en fait une fonction de bibliothèque superposée à l’appel système sous-jacent clone ()." - en général, cela s'applique à tout appel système. En réalité, les programmeurs appellent presque toujours dans libc des fonctions nommées d'après l'appel système. Cela est dû au fait que passer un appel système réel directement à partir de C nécessite une magie spécifique à la plate-forme (généralement en forçant une sorte d’interruption du processeur, dépend de l’architecture ABI) et du code machine préférable de le déléguer à libc.
Celada
1
@Celada - oui, d'accord. C'est juste que les man 2 clonemots sont formulés exactement de cette façon, ce qui, je pensais, confondait le problème et empêchait le questionneur d'obtenir une bonne réponse.
Bruce Ediger
2
Je crois que la page de manuel signifie que la liste d'arguments de la clonefonction de bibliothèque diffère considérablement de la liste d'arguments acceptée par l'appel système sous-jacent. En particulier, l’appel système revient toujours deux fois sur la même pile, comme le fait habituellement fork; tous les arguments liés à la pile enfant sont gérés strictement dans l'espace utilisateur. Voir, par exemple, sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…
zwol le
1
Je voulais donner à votre réponse la meilleure réponse parce que ça déchire, mais le troupeau m'a influencé et je suis parti avec la première réponse. Elle obtient des points pour le temps de réponse. Merci pour votre explication.
Gregg Leventhal
6
fork()est juste un ensemble particulier d'indicateurs à l'appel système clone(). clone()est assez général pour créer un "processus" ou un "fil" ou même des choses étranges qui se situent quelque part entre les processus et les threads (par exemple, des "processus" différents qui partagent la même table de descripteur de fichier).
Essentiellement, pour chaque "type" d'informations associé à un contexte d'exécution dans le noyau, clone()vous pouvez choisir d'aliaser ces informations ou de les copier. Les threads correspondent aux alias, les processus correspondent à la copie. En spécifiant des combinaisons intermédiaires de drapeaux à clone(), vous pouvez créer des choses étranges qui ne sont ni des threads ni des processus. Vous ne devriez normalement pas faire cela, et j'imagine que le développement du noyau Linux a fait l’objet d’un débat sur la possibilité de prévoir un mécanisme aussi général que clone().
Il semble que deux
clone()
éléments flottent dans Linux 2.6Il y a un appel système:
C'est le "clone ()" décrit en faisant
man 2 clone
.Si vous lisez suffisamment cette page de manuel, vous verrez ceci:
Apparemment, vous êtes censé implémenter le threading en utilisant la "fonction de bibliothèque" superposée à l'appel système qui porte un nom identique.
J'ai écrit un programme court:
Compilez-le avec:
c99 -Wall -Wextra
et parcourez-lestrace -f
pour voir ce que font réellement les appels système faisant appel à la fourchette. Je l'ai obtenustrace
sur une machine Linux 2.6.18 (CPU x86_64):Aucun appel "fork" n'apparaît dans la
strace
sortie. L'clone()
appel qui apparaît dans lastrace
sortie a des arguments très différents de ceux du clone man-page.child_stack=0
comme le premier argument est différent deint (*fn)(void *)
.Il semble que l'
fork(2)
appel système soit implémenté en termes réelsclone()
, tout comme la "fonction de bibliothèque"clone()
est implémentée. Le réelclone()
a un ensemble d'arguments différent du clone man-page.De manière simpliste, vos deux déclarations apparemment contradictoires à propos de
fork()
etclone()
sont correctes. Le "clone" impliqué est différent, cependant.la source
man 2 clone
mots sont formulés exactement de cette façon, ce qui, je pensais, confondait le problème et empêchait le questionneur d'obtenir une bonne réponse.clone
fonction de bibliothèque diffère considérablement de la liste d'arguments acceptée par l'appel système sous-jacent. En particulier, l’appel système revient toujours deux fois sur la même pile, comme le fait habituellementfork
; tous les arguments liés à la pile enfant sont gérés strictement dans l'espace utilisateur. Voir, par exemple, sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…fork()
est juste un ensemble particulier d'indicateurs à l'appel systèmeclone()
.clone()
est assez général pour créer un "processus" ou un "fil" ou même des choses étranges qui se situent quelque part entre les processus et les threads (par exemple, des "processus" différents qui partagent la même table de descripteur de fichier).Essentiellement, pour chaque "type" d'informations associé à un contexte d'exécution dans le noyau,
clone()
vous pouvez choisir d'aliaser ces informations ou de les copier. Les threads correspondent aux alias, les processus correspondent à la copie. En spécifiant des combinaisons intermédiaires de drapeaux àclone()
, vous pouvez créer des choses étranges qui ne sont ni des threads ni des processus. Vous ne devriez normalement pas faire cela, et j'imagine que le développement du noyau Linux a fait l’objet d’un débat sur la possibilité de prévoir un mécanisme aussi général queclone()
.la source