web-dev-qa-db-fra.com

Quelles ressources sont partagées entre les threads?

Récemment, on m'a posé une question dans une interview: quelle est la différence entre un processus et un fil. Vraiment, je ne connaissais pas la réponse. J'ai réfléchi pendant une minute et j'ai donné une réponse très étrange. 

Les threads partagent la même mémoire que les processus. Après avoir répondu à cette question, l'interviewer m'a adressé un sourire diabolique et m'a tiré les questions suivantes:

Q. Connaissez-vous les segments dans lesquels un programme est divisé?

Ma réponse: yep (j'ai pensé que c'était facile) Stack, Data, Code, Heap

Q. Alors, dites-moi: quels segments partagent les threads?

Je ne pouvais pas répondre à cette question et j'ai fini par les dire toutes.

S'il vous plaît, quelqu'un peut-il présenter les réponses correctes et impressionnantes pour la différence entre un processus et un fil?

215
Xinus

Vous êtes à peu près correct, mais les threads partagent tous les segments sauf la pile. Les threads ont des piles d'appels indépendantes, mais la mémoire des autres piles de threads est toujours accessible et, en théorie, vous pouvez conserver un pointeur sur la mémoire dans le cadre de pile local d'un autre thread (même si vous devriez probablement trouver un meilleur emplacement pour mettre cette mémoire!).

145
Greg Hewgill

De Wikipedia (Je pense que cela ferait une très bonne réponse pour l'intervieweur: P)

Les fils diffèrent des fils traditionnels Système d'exploitation multitâche processus en ce que:

  • les processus sont généralement indépendants, alors que les threads sont des sous-ensembles d'un fichier processus
  • les processus contiennent des informations d'état considérables, alors que plusieurs threads dans un état de partage de processus également comme mémoire et autres ressources
  • les processus ont des espaces d'adressage séparés, alors que les threads partagent leur espace d'adressage
  • les processus n'interagissent que par le biais des processus interprocessus fournis par le système mécanismes de communication.
  • La commutation de contexte entre les threads dans le même processus est généralement plus rapide que la commutation de contexte entre processus.
48
Jorge Córdoba

Ce qu'il faut vraiment souligner, c'est qu'il y a vraiment deux aspects à cette question: l'aspect théorique et l'aspect de la mise en œuvre.

Commençons par l’aspect théorique. Vous devez comprendre ce qu'est un processus sur le plan conceptuel pour comprendre la différence entre un processus et un fil et ce qui est partagé entre eux.

La section 2.2.2 Le modèle de fil classique dans Systèmes d'exploitation modernes 3e de Tanenbaum:

Le modèle de processus est basé sur deux concepts indépendants: ressource regroupement et exécution. Parfois, il est utile de les séparer; c'est là que les fils entrent en jeu .... 

Il continue:

Une façon de considérer un processus est qu’il est une façon de regrouper les ressources connexes. Un processus a un espace d'adressage contenant le texte et les données du programme, ainsi que d’autres ressources. Celles-ci la ressource peut inclure des fichiers ouverts, des processus enfants, des alarmes en attente, gestionnaires de signaux, informations comptables, etc. En les mettant ensemble sous forme de processus, ils peuvent être gérés plus facilement . L'autre concept qu'un processus a est un thread d'exécution, généralement raccourci pour simplement enfiler. Le thread a un compteur de programme qui conserve piste de l'instruction à exécuter ensuite. Il a des registres, qui tenir ses variables de travail actuelles. Il a une pile, qui contient le historique d'exécution, avec un cadre pour chaque procédure appelée mais pas encore revenu de. Bien qu'un thread doive s'exécuter dans un processus, le fichier Le fil et son processus sont des concepts différents et peuvent être traités séparément. Les processus sont utilisés pour regrouper des ressources; fils sont les entités dont l'exécution est planifiée sur la CPU.

Plus bas, il fournit le tableau suivant:

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

Ce qui précède est ce dont vous avez besoin pour que les threads fonctionnent. Comme d'autres l'ont souligné, les segments, par exemple, sont des détails d'implémentation dépendants du système d'exploitation.

38
Robert S. Barnes

Dites à l'intervieweur que cela dépend entièrement de la mise en œuvre du système d'exploitation.

Prenez Windows x86 par exemple. Il n'y a que 2 segments [1], Code et Données. Et ils sont tous deux mappés sur l'ensemble de l'espace d'adressage de 2 Go (linéaire, utilisateur). Base = 0, limite = 2 Go. Ils en auraient créé un, mais x86 ne permet pas à un segment d'être à la fois en lecture/écriture et en exécution. Ils en ont donc créé deux et ont défini CS pour qu'il pointe vers le descripteur de code et le reste (DS, ES, SS, etc.) pour désigner l'autre [2]. Mais les deux pointent sur les mêmes choses!

La personne qui vous a interviewé a fait une hypothèse cachée qu’elle n’a pas déclarée, et c’est un truc stupide à tirer.

Donc concernant 

Q. Alors, dites-moi quel fil de segment partager?

Les segments ne sont pas pertinents pour la question, du moins sous Windows. Les threads partagent tout l'espace d'adressage. Il y a seulement 1 segment de pile, SS, et il pointe exactement sur les mêmes fonctions que DS, ES et CS [2]. C'est à dire. l'espace utilisateur entièrement sanglant. 0-2GB. Bien sûr, cela ne signifie pas que les threads ne disposent que d’une pile. Naturellement, chacun a sa propre pile, mais les segments x86 ne sont pas utilisés à cette fin.

Peut-être que * nix fait quelque chose de différent. Qui sait. La prémisse sur laquelle la question était basée était brisée.


  1. Au moins pour l'espace utilisateur.
  2. De ntsd notepad: cs=001b ss=0023 ds=0023 es=0023
26
Alex Budovski

Généralement, les threads sont appelés processus de poids léger. Si nous divisons la mémoire en trois sections, il s'agira de: Code, données et pile . Chaque processus a ses propres sections de code, de données et de pile. Pour réduire le temps de changement de contexte, les utilisateurs ont mis au point le concept de thread, qui partage le segment de données et de code avec un autre thread/processus et qui possède son propre segment STACK.

17
Nimish Thakkar

Un processus a des segments de code, de données, de tas et de pile. Désormais, le pointeur d'instruction (IP) d'un thread OR renvoie au segment de code du processus. Les segments de données et de segments de mémoire sont partagés par tous les threads. Maintenant, qu'en est-il de la zone de pile? Quelle est en réalité la zone de pile? C’est une zone créée par le processus juste pour son thread à utiliser ... parce que les piles peuvent être utilisées beaucoup plus rapidement que les tas, etc. La zone de pile du processus est divisée en thread La zone de pile du processus est divisée en 3 parties et chacune est attribuée aux 3 threads. En d'autres termes, lorsque nous disons que chaque thread a sa propre pile, cette pile est en réalité une partie de la zone de pile de processus allouée à chaque thread. Lorsqu'un thread termine son exécution, la pile du thread est récupérée par le processus. En fait, non seulement la pile d'un processus est divisée en threads, mais tous les registres utilisés par un thread comme SP, PC et les registres d'état sont les registres du processus. Ainsi, en matière de partage, les zones de code, de données et de segment de mémoire sont partagées, tandis que la zone de pile est simplement divisée entre les threads.

16

Les threads partagent les segments de code et de données et le segment de mémoire, mais ils ne partagent pas la pile.

12
Kevin Peterson

Les threads partagent des données et du code, contrairement aux processus. La pile n'est pas partagée pour les deux.

Les processus peuvent également partager de la mémoire, plus précisément du code, par exemple après un Fork(), mais il s'agit d'un détail d'implémentation et d'optimisation (du système d'exploitation). Le code partagé par plusieurs processus deviendra (espérons-le) dupliqué lors de la première écriture dans le code - cela s'appelle copie en écriture . Je ne suis pas sûr de la sémantique exacte du code des threads, mais je suppose du code partagé.

 Processus de fil 

 Stack privé privé 
 Données privées partagées 
 Code privé1   partagé2

1 Le code est logically private mais peut être partagé pour des raisons de performances .2 Je ne suis pas sûr à 100%.

5
Daniel Brückner

Les fils partagent tout [1]. Il y a un espace d'adressage pour l'ensemble du processus.

Chaque thread a sa propre pile et ses propres registres, mais les piles de tous les threads sont visibles dans l'espace d'adressage partagé.

Si un thread alloue un objet sur sa pile et envoie l'adresse à un autre thread, ils auront un accès égal à cet objet.


En fait, je viens de remarquer un problème plus vaste: je pense que vous confondez deux utilisations du segment Word segment .

Le format de fichier d'un exécutable (par exemple, ELF) comporte des sections distinctes, appelées segments, contenant du code compilé (texte), des données initialisées, des symboles de l'éditeur de liens, des informations de débogage, etc. ici, puisque ce ne sont que des constructions d’exécution.

Ces segments de fichier binaires peuvent être mappés séparément dans l'espace d'adressage du processus, avec des autorisations différentes (par exemple, un exécutable en lecture seule pour le code/texte et un copieur sur écriture non exécutable pour les données initialisées).

Les zones de cet espace d'adressage sont utilisées à des fins différentes, telles que l'allocation de tas et les piles de threads, par convention (appliquée par les bibliothèques d'exécution de votre langue). Cependant, il ne s'agit que de mémoire, et probablement pas segmenté sauf si vous utilisez le mode virtuel 8086. La pile de chaque thread est un bloc de mémoire alloué au moment de la création du thread, l'adresse top de la pile actuelle étant stockée dans un registre de pointeur de pile. Chaque thread conserve son propre pointeur de pile ainsi que ses autres registres.


[1] OK, je sais: masques de signaux, TSS/TSD, etc. L'espace d'adressage, y compris tous ses segments de programme mappés, est toujours partagé.

4
Useless

Dans un framework x86, on peut diviser autant de segments (jusqu'à 2 ^ 16-1). Les directives ASM SEGMENT/ENDS le permettent, et les opérateurs SEG et OFFSET permettent l’initialisation des registres de segments. CS: IP sont généralement initialisés par le chargeur, mais pour DS, ES, SS, l’application est responsable de l’initialisation . De nombreux environnements autorisent les "définitions de segment simplifiées" telles que .code, .data, .bss,. etc., et, en fonction également du "modèle de mémoire" (petit, grand, compact, etc.), le chargeur initialise les registres de segments en conséquence. Habituellement, les segments .data, .bss, .stack et autres segments habituels (je n’ai pas fait cela depuis 20 ans et je ne me souviens pas de tout) sont regroupés dans un seul groupe - c’est pourquoi, habituellement, DS, ES et SS pointent vers même domaine, mais ce n’est que pour simplifier les choses.

En général, tous les registres de segments peuvent avoir des valeurs différentes au moment de l'exécution . Ainsi, la question de l'interview était la bonne: lequel des codes CODE, DATA et STACK est partagé entre les threads. La gestion de tas est autre chose - c'est simplement une séquence d'appels au système d'exploitation. Mais que se passe-t-il si vous n'avez pas du tout de système d'exploitation, comme dans un système embarqué - pouvez-vous toujours avoir un nouveau/supprimer dans votre code?

Mon conseil aux jeunes - lisez un bon livre de programmation pour l’Assemblée. Il semble que les programmes universitaires soient assez pauvres à cet égard. 

2
George

Le thread partage le tas (il existe une recherche sur le tas spécifique au thread) mais l'implémentation actuelle partage le tas. (et bien sur le code)

1
Dani

Outre la mémoire globale, les threads partagent également un certain nombre d'autres attributs (c’est-à-dire que ces attributs sont globaux pour un processus, plutôt que spécifiques à un thread). Ces attributs incluent les suivants:

  • iD de processus et ID de processus parent;
  • identifiant de groupe de processus et identifiant de session;
  • terminal de contrôle;
  • traiter les informations d'identification (ID utilisateur et groupe);
  • descripteurs de fichiers ouverts;
  • verrous d'enregistrement créés à l'aide de fcntl();
  • dispositions du signal;
  • informations relatives au système de fichiers: umask, répertoire de travail actuel et répertoire racine;
  • des temporisateurs à intervalles (setitimer()) et des temporisateurs POSIX (timer_create());
  • Valeurs d'annulation du sémaphore System V (semadj) (Section 47.8);
  • ressources limitées;
  • Temps CPU consommé (tel que retourné par times());
  • ressources consommées (telles que retournées par getrusage()); et
  • Valeur intéressante (définie par setpriority() et Nice()).

Le .__ parmi les attributs distincts pour chaque thread. Suivant:

  • iD de thread (Section 29.5);
  • masque de signalisation;
  • données spécifiques aux threads (Section 31.3);
  • pile de signaux de remplacement (sigaltstack());
  • la variable errno;
  • environnement en virgule flottante (voir fenv(3));
  • politique et priorité de planification en temps réel (articles 35.2 et 35.3);
  • Affinité CPU (spécifique à Linux, décrite dans Section 35.4);
  • capacités (spécifiques à Linux, décrites au chapitre 39); et
  • pile (variables locales et informations de liaison d’appel de fonction).

Extrait de: L'interface de programmation Linux: Un manuel de programmation système Linux et UNIX, Michael Kerrisk , page 619

0
snr

En cours, tous les threads partagent des ressources système telles que la mémoire de tas, etc., tandis que Thread possède sa propre pile.

Donc, vos ans devraient être de la mémoire de tas que tous les threads partagent pour un processus.

0
roshni