Linus Torvalds (torvalds@cs.helsinki.fi)
Mar., 6 août 1996 12:47:31 +0300 (EET DST)
Messages triés par: [date] [thread] [sujet] [auteur]
Message suivant: Bernd P. Ziller: "Re: Oups dans get_hash_table"
Message précédent: Linus Torvalds: "Re: commande de demande d'E / S"
Le lundi 5 août 1996, Peter P. Eiserloh a écrit:
Nous devons garder clair le concept de threads. Trop de gens semblent confondre un fil avec un processus. La discussion suivante ne reflète pas l'état actuel de Linux, mais est plutôt une tentative de rester à une discussion de haut niveau.
NON!
Il n'y a AUCUNE raison de penser que les «fils» et les «processus» sont des entités distinctes. C'est ainsi que cela se fait traditionnellement, mais je pense personnellement que c'est une erreur majeure de penser de cette façon. La seule raison de penser de cette façon est le bagage historique.
Les threads et les processus ne sont en réalité qu'une seule chose: un "contexte d'exécution". Essayer de distinguer artificiellement différents cas est tout simplement autolimitant.
Un «contexte d'exécution», ci-après appelé COE, n'est que le conglomérat de tout l'état de ce COE. Cet état comprend des éléments comme l'état du processeur (registres, etc.), l'état MMU (mappages de pages), l'état d'autorisation (uid, gid) et divers "états de communication" (fichiers ouverts, gestionnaires de signaux, etc.). Traditionnellement, la différence entre un "thread" et un "processus" a été principalement qu'un thread a un état CPU (+ éventuellement un autre état minimal), tandis que tout le reste du contexte provient du processus. Cependant, ce n'est
qu'une façon de diviser l'état total du COE, et rien ne dit que c'est la bonne façon de le faire. Se limiter à ce genre d'image est tout simplement stupide.
La façon dont Linux pense à ce sujet (et la façon dont je veux que les choses au travail) est qu'il n'y a pas une telle chose comme un « processus » ou un « fil ». Il n'y a que la totalité du COE (appelé «tâche» par Linux). Différents COE peuvent partager des parties de leur contexte entre eux, et un sous-ensemble - de ce partage est la configuration traditionnelle "thread" / "processus", mais cela devrait vraiment être considéré comme SEULEMENT un sous-ensemble (c'est un sous-ensemble important, mais cette importance vient pas de conception, mais de normes: nous voulons évidemment exécuter des programmes de threads conformes aux normes sur Linux aussi).
En bref: ne concevez PAS autour de la façon de penser fil / processus. Le noyau doit être conçu autour de la façon de penser COE, puis la bibliothèque pthreads peut exporter l'interface pthreads limitée aux utilisateurs qui souhaitent utiliser cette façon de voir les COE.
Juste comme un exemple de ce qui devient possible lorsque vous pensez COE par opposition à thread / processus:
- Vous pouvez faire un programme "cd" externe, quelque chose qui est traditionnellement impossible sous UNIX et / ou process / thread (exemple idiot, mais l'idée est que vous pouvez avoir ce genre de "modules" qui ne sont pas limités à l'UNIX traditionnel / configuration des threads). Fait une:
clone (CLONE_VM | CLONE_FS);
enfant: execve ("external-cd");
/ * le "execve ()" dissociera la VM, donc la seule raison pour laquelle nous avons utilisé CLONE_VM était d'accélérer le clonage * /
- Vous pouvez faire "vfork ()" naturellement (cela nécessite un support minimal du noyau, mais ce support correspond parfaitement à la façon de penser de l'AUC):
clone (CLONE_VM);
enfant: continuer à courir, éventuellement execve ()
mère: attendez execve
- vous pouvez faire des "démons IO" externes:
clone (CLONE_FILES);
enfant: descripteurs de fichiers ouverts, etc.
mère: utilisez le fd de l'enfant ouvert et vv.
Tout ce qui précède fonctionne parce que vous n'êtes pas lié à la façon de penser du fil / processus. Pensez à un serveur web par exemple, où les scripts CGI se font comme des "threads d'exécution". Vous ne pouvez pas faire cela avec des threads traditionnels, car les threads traditionnels doivent toujours partager tout l'espace d'adressage, vous devez donc lier tout ce que vous avez toujours voulu faire dans le serveur Web lui-même (un «thread» ne peut pas s'exécuter un autre exécutable).
En considérant cela comme un problème de "contexte d'exécution", vos tâches peuvent désormais choisir d'exécuter des programmes externes (= séparer l'espace d'adressage du parent), etc. si elles le souhaitent, ou elles peuvent par exemple tout partager avec le parent, sauf pour les descripteurs de fichiers (pour que les sous-"threads" puissent ouvrir beaucoup de fichiers sans que le parent ait à s'en soucier: ils se ferment automatiquement lorsque le sous-"thread" se termine, et il n'utilise pas les fd dans le parent) .
Pensez à un "inetd" fileté, par exemple. Vous voulez un faible overhead fork + exec, donc avec la méthode Linux vous pouvez au lieu d'utiliser un "fork ()" vous écrivez un inetd multi-thread où chaque thread est créé avec juste CLONE_VM (partager l'espace d'adressage, mais ne pas partager le fichier descripteurs, etc.). L'enfant peut alors s'exécuter s'il s'agissait d'un service externe (rlogind, par exemple), ou peut-être qu'il s'agissait d'un des services internes inetd (echo, timeofday), auquel cas il fait simplement sa chose et se termine.
Vous ne pouvez pas faire cela avec "thread" / "processus".
Linus