Threads vs processus (fourchus)

9

Les applications Linux génèrent généralement fork puis exec (avec execve ()), mais les applications Java et certains MPM Apache utilisent le threading. Si forking, utilise le fork + exec pour générer un processus, quelle est la version de haut niveau pour le threading? Comment JVM ou Worker MPM génèrent des threads?

Gregg Leventhal
la source
2
Découvrez Stackoverflow. Il y a plusieurs questions et réponses qui ont expliqué une partie de cela.
Henk Langeveld

Réponses:

13

L'idée derrière les threads et les processus est à peu près la même: vous bifurquez le chemin d'exécution. Sinon, les threads et les processus diffèrent dans des choses comme la mémoire. C'est-à-dire que les processus ont un espace VM différent tandis que les threads partagent tout ce qui existait avant la division.

Sous-jacent à la fois au travail de threading et de forking à l'aide de l'appel clone () (clone man 2):

Contrairement à fork (2), clone () permet au processus enfant de partager des parties de son contexte d'exécution avec le processus appelant, comme l'espace mémoire, la table des descripteurs de fichiers et la table des gestionnaires de signaux. (Notez que sur cette page de manuel, "processus appelant" correspond normalement à "processus parent". Mais voir la description de CLONE_PARENT ci-dessous.)

L'utilisation principale de clone () est d'implémenter des threads: plusieurs threads de contrôle dans un programme qui s'exécutent simultanément dans un espace mémoire partagé.

Les différences proviennent des drapeaux qui sont passés à clone (). Comme vous pouvez le voir sur la page de manuel, fork et threading ne sont qu'un ensemble de paramètres prédéfinis à clone (). Cependant, on peut aussi faire des trucs personnalisés avec.

V13
la source
1
Uhm? Quelle? Veuillez relire à peu près tous les livres sur le sujet, car l'espace mémoire séparé pour les processus est un gros problème. Aide également à "attraper" le code qui se bloque, tandis que le noyau va simplement tuer un processus où un thread individuel se détourne / transgresse.
0xC0000022L
3
@ 0xC0000022L votre argument ne contredit pas la réponse, comme il me semble.
Ruslan
1
@Ruslan: Je vous prie de différer: "L'idée [...] est à peu près la même"? L'idée derrière les threads est en effet la concurrence, mais pour les processus, c'est une tout autre histoire.
0xC0000022L
4
@ 0xC0000022L Vous avez manqué la partie importante de la réponse de V13: "Vous bifurquez le chemin d'exécution" - la question est de savoir comment les threads sont générés, pas quelle est la différence entre les threads et les processus
Izkata
@Izkata: pas du tout. Je pense simplement que ce n'est pas une affirmation correcte.
0xC0000022L
8

La plupart des systèmes d'exploitation (OS) multiprocessing non Unix utilisent un appel "spawn ()" ou quelque chose de similaire pour générer un nouveau processus OS ou un flux de contrôle. Spawn () a tendance à être un appel très complexe, avec beaucoup d'options et beaucoup de frais généraux. L'une des innovations d'Unix a été de fournir une méthode de création de processus beaucoup plus économique - fork (). Unix s'est occupé des nombreuses options nécessaires à spawn () en autorisant des quantités arbitraires de traitement avant l'autre moitié de spawn (), avec exec ().

Comme Unix et ses variantes étaient de plus en plus utilisés, la création de processus à faible surcharge s'est avérée utile et a été utilisée. En fait, il était tellement utilisé que les gens voulaient des frais généraux encore plus bas pour créer des processus, et ainsi l'idée de «threads» était née. À l'origine, les threads étaient entièrement gérés par le processus d'origine (et des programmes comme la JVM peuvent le faire avec des «threads verts»); mais la gestion de la planification multi-thread est délicate et a souvent été mal effectuée. Il existe donc un moyen intermédiaire plus facile de faire des threads, où le système d'exploitation gère la planification, mais certains frais généraux sont enregistrés en partageant (généralement) l'espace d'adressage entre les threads.

Il est difficile de répondre à votre question car il existe plusieurs concepts différents mais liés qui sont tous des «fils», et pour plus de détails, vous avez besoin d'un adjectif pour décrire celui auquel vous faites référence. D'un autre côté, comprendre les différences vous mènera probablement à la réponse spécifique que vous souhaitez. Recherchez des éléments tels que «processus légers», «threads utilisateur» et «rfork ()» pour plus d'informations.

mpez0
la source
1
"la gestion de la planification multi-thread est délicate et a souvent été mal effectuée". L'implémentation de threads de l'espace utilisateur n'est pas un problème. Le problème avec les threads de l'espace utilisateur est que si un thread effectue un appel système bloquant, tous les threads sont bloqués. La seule façon d'éviter cela est d'utiliser des threads au niveau du système.
Bakuriu
1
Fait intéressant, Windows n'a pas inclus cette innovation d'Unix: elle n'a CreateProcess()rien de semblable à fork().
Ruslan
2
@Bakuriu - recherchez l'un des nombreux articles sur la création d'ordonnanceurs multiprocesseurs, le maintien de l'équité, la prévention de la famine, la gestion des priorités, etc. Planifier des exemples non triviaux est difficile.
mpez0
@Ruslan: on peut bifurquer sous Windows, cela ne fait tout simplement pas partie de l'API Win32. Lisez «L'API native Windows NT / 2000» par Nebbett. Il a une implémentation qui imite fork().
0xC0000022L
3

Les threads et les fourches sont en fait deux concepts différents, qui existent tous deux dans les systèmes Unix / Linux (et qui peuvent tous deux être utilisés en C / C ++).

L'idée d'un fork () est (très fondamentalement) la création d'un processus séparé qui a le même code d'exécution que le processus parent et qui commence son exécution sur la ligne fork. Le but de l'utilisation de fourches avec des fonctions exec est que les fonctions exec ferment le processus qui les a appelées à leur fin. Ainsi, vous bifurquez habituellement, obtenez le PID de chaque processus (l'enfant est toujours 0), et faites attendre le parent jusqu'à ce que l'enfant ait fini d'exécuter la fonction exec.

Les threads sont utilisés pour le parallélisme (rappelez-vous que le parent attend l'enfant, généralement, dans un programme fourchu). Un thread, tel que pthread en C / C ++ (effectuez une recherche Google), s'exécutera en parallèle avec le processus principal et peut partager des variables globales et des fonctions globales avec le programme d'origine. Étant donné que les threads Java se comportent de la même manière, j'imagine qu'ils agissent plus comme ces threads que comme un processus de forking.

Fondamentalement, il existe une différence entre le forking et le filetage. Ils font des choses distinctement différentes (bien que semblant similaires). Ces concepts peuvent être difficiles à comprendre, mais vous pouvez les apprendre grâce à des recherches (approfondies) si vous avez un désir sincère de les comprendre.

EDIT # 1

Veuillez voir ces exemples de la façon dont les fourches et les threads peuvent être appelés et utilisés. Veuillez noter le comportement des fonctions exec et leurs effets sur le programme principal.

http://www.jdembrun.com:4352/computerScience/forkVSthread.zip

jaredad7
la source
2
Fork (avec ou sans exec) peut également être utilisé pour le parallélisme. Je ne suis pas sûr de ce que vous entendez par «les fonctions exécutives ferment le processus qui les a appelées lorsqu'elles se terminent», l'exécution est terminée depuis longtemps à la fin du processus. Est également pthreadune API, pas une implémentation de thread.
Mat
Sur la fourchette, je cite mon professeur de système d'exploitation. Selon ce qu'il nous a dit, oui, la fourche pourrait être utilisée pour fonctionner en parallèle, mais, si elle utilisait une fonction exec, ce serait la dernière. Quant à pthread, il s'agissait d'un exemple.
jaredad7
Exec serait le dernier appel dans le code de l'appelant, pas la dernière instruction du processus forké. Le processus bifurqué continuerait d'exécuter le code exécuté.
Mat
Vos commentaires m'ont incité à tester ces choses. J'ai écrit quelques programmes c ++ qui démontrent le comportement des fonctions exec et leurs effets sur les programmes lorsqu'ils sont utilisés dans les forks contre les threads. Veuillez voir la modification ci-dessus.
jaredad7
J'ai bien peur que la plupart des gens ne prennent pas la peine de télécharger ça. Vos exemples n'illustrent pas non plus les différences intéressantes entre les modèles, qui sont principalement liées au partage (ou non) de l'espace d'adressage.
Mat
1

La JVM et Apache MPM s'appuient sur le noyau pour les threads natifs. Autrement dit, ils utilisent le système d'exploitation pour les planifier. Bien sûr, les deux ont besoin de leur propre API pour suivre les choses.

Stackoverflow a déjà plusieurs questions à ce sujet:

  1. Threads natifs JVM , consultez cette réponse pour plus de détails.

  2. Apache a deux types de MPM: Prefork, avec un processus par thread, et Worker, qui gère plusieurs threads: les MPM Apache . Consultez la référence àcodebucket

Henk Langeveld
la source
1

Si forking, utilise le fork + exec pour générer un processus, quelle est la version de haut niveau pour le threading? Comment JVM ou Worker MPM génèrent des threads?

C'est spécifique à la plate-forme, mais sous Linux et je suppose que de nombreux autres systèmes conformes POSIX utilisent l'implémentation locale de pthreads , une API de threading utilisateur. Par exemple:

#include <pthread.h>

pthread_t tid;
pthread_create(&tid, NULL, somefunc, NULL);

Démarre un nouveau thread appelant somefunccomme premier point d'exécution.

Vous pouvez également créer des threads - distincts des fourches en ce sens qu'ils partagent le même espace de mémoire de tas global du processus parent, au lieu d'en obtenir une copie en double (mais notez que les threads s'exécutent chacun avec une mémoire de pile indépendante qui leur est propre) - avec l' clone()appel système, qui est ce sur quoi pthreads est construit.

boucle d'or
la source