standard - table des descripteur




Quelqu'un peut-il expliquer une description simple concernant le descripteur de fichier après fork()? (2)

Dans "Programmation avancée dans l'environnement Unix", 2e édition, par W. Richard Stevens.

Section 8.3 fonction de fourche.

Voici la description:

Il est important que le parent et l'enfant partagent le même décalage de fichier.

Considérons un processus qui forge un enfant, puis attend que celui-ci se termine. Supposons que les deux processus écrivent sur la sortie standard dans le cadre de leur traitement normal. Si le parent a sa sortie standard redirigée (par un shell, peut-être), il est essentiel que le décalage du fichier parent soit mis à jour par l'enfant lorsque l'enfant écrit sur la sortie standard.

[1. Qu'est-ce que ça veut dire? Si la sortie std du parent est redirigée vers un "fichier1" par exemple, alors qu'est-ce que l'enfant doit mettre à jour après que l'enfant ait écrit? offset de sortie std d'origine ou redirigée de sortie (ie fichier1)? Ne peut pas être le plus tard, non?]

[2. Comment se passe la mise à jour? par enfant explicitement, par OS implicitement, par descripteur de fichier lui-même? Après fork, je pensais que parent et enfant suivaient leur propre chemin et avaient leur propre descripteur de fichier. Alors, comment l'enfant met-il à jour le côté parent?]

Dans ce cas, l'enfant peut écrire sur la sortie standard pendant que le parent l'attend; à la fin de l'enfant, le parent peut continuer à écrire sur la sortie standard, sachant que sa sortie sera ajoutée à ce que l'enfant a écrit. Si le parent et l'enfant ne partageaient pas le même décalage de fichier, ce type d'interaction serait plus difficile à réaliser et exigerait des actions explicites du parent.

Si parent et enfant écrivent tous deux dans le même descripteur, sans aucune forme de synchronisation, par exemple en demandant au parent d'attendre l'enfant, leur sortie sera mélangée (en supposant qu'il s'agisse d'un descripteur ouvert avant le fork). Bien que cela soit possible, ce n'est pas le mode de fonctionnement normal.

Il y a deux cas normaux pour traiter les descripteurs après un fork.

  1. Le parent attend que l'enfant termine. Dans ce cas, le parent n'a rien à faire avec ses descripteurs. Lorsque l'enfant se termine, tous les descripteurs partagés que l'enfant lit ou écrit sur son fichier verront leurs décalages de fichiers mis à jour en conséquence.

  2. Le parent et l'enfant vont tous deux. Ici, après le fork, le parent ferme les descripteurs dont il n'a pas besoin et l'enfant fait la même chose. De cette façon, ni l'un ni l'autre n'interfère avec les descripteurs ouverts de l'autre. Ce scénario est souvent le cas avec les serveurs de réseau. "

[3. Lorsque fork () est invoqué, tout ce que je comprends est que l'enfant obtient une COPIE de ce que le parent a, descripteur de fichier dans ce cas, et fait son travail. Si un décalage est apporté au descripteur de fichier par ce parent et cet enfant, cela ne peut être que parce que le descripteur se souvient du décalage lui-même. Ai-je raison?]

Désolé je suis un peu nouveau pour les concepts.

De l'aide? Merci.


Dans la même section, de livre, il y a un diagramme montrant trois tables qui sont là quand un fichier est ouvert.

La table filedescriptor de l'utilisateur (partie de l'entrée de la table de processus), la table des fichiers et des inodes (table v-node). Maintenant, une entrée filedescriptor (qui est un index de la table de descripteurs de fichiers) pointe vers une entrée de table de fichiers, qui pointe vers une entrée de table inode.
Maintenant, le fichier offset (la position à partir de laquelle la lecture / écriture suivante se produit) se trouve dans la table File.

Donc, disons que vous avez un fichier ouvert dans parent, cela signifie qu'il a aussi un descripteur, une entrée de table de fichier et une référence d'inode.
Maintenant, lorsque vous créez un enfant, le tableau de descripteur de fichier est copié pour l'enfant. Ainsi, le nombre de références dans l'entrée de la table de fichiers (pour ce descripteur ouvert) est augmenté, ce qui signifie qu'il existe maintenant deux références pour la même entrée de la table de fichiers.

Ce descripteur est désormais disponible dans parent et enfant, pointant vers la même entrée de la table de fichiers, partageant ainsi le décalage. Maintenant que vous avez cette expérience, laissez-nous voir vos questions,

  1. Qu'est-ce que ça veut dire? Si la sortie std du parent est redirigée vers un "fichier1" par exemple, alors qu'est-ce que l'enfant doit mettre à jour après que l'enfant ait écrit? offset de sortie std d'origine ou redirigée de sortie (ie fichier1)? Ne peut pas être le dernier, non?]

L'enfant n'a explicitement pas besoin de mettre à jour. L'auteur du livre essaie de
dire que, supposons que la sortie standard des parents soit redirigée vers un fichier et qu'un appel soit effectué. Après cela, le parent est en attente. Le descripteur est maintenant dupliqué, c'est-à-dire que le décalage du fichier est également partagé. Maintenant, chaque fois que l'enfant écrit quelque chose en standard, les données écrites sont enregistrées dans le fichier redirigé. Le décalage est automatiquement incrémenté par l’écriture.

Maintenant, disons que l'enfant sort. Le parent sort donc de l'attente et écrit quelque chose sur la sortie standard (qui est redirigé). Maintenant, la sortie de l'appel d'écriture du parent sera placée -> après les données écrites par l'enfant. Why -> puisque la valeur actuelle de l'offset est maintenant modifiée après l'écriture de l'enfant.

 Parent ( )
  {
    open a file for writing, that is get the 
    descriptor( say fd);
    close(1);//Closing stdout
    dup(fd); //Now writing to stdout  means writing to the file
    close(fd)
        //Create a child that is do a  fork call.
    ret = fork();
    if ( 0 == ret )
    {
        write(1, "Child", strlen("Child");
        exit ..
    }
        wait(); //Parent waits till child exit.

         write(1, "Parent", strlen("Parent");
    exit ..
}

PL. voir le pseudo-code ci-dessus, les données finales que contient le fichier ouvert seront ChildParent. Donc, vous voyez que le décalage du fichier a été modifié lorsque l'enfant a écrit et que cela était possible pour l'appel en écriture du parent, puisque l'offset est partagé.

2.Comment la mise à jour est-elle effectuée? par enfant explicitement, par OS implicitement, par descripteur de fichier lui-même? Après fork, je pensais que parent et enfant suivaient leur propre chemin et avaient leur propre descripteur de fichier. Alors, comment l'enfant met-il à jour le côté parent?]

Now I think the answer is clear-> by the system call that is by the OS.

[3. Lorsque fork () est invoqué, tout ce que je comprends est que l'enfant obtient une COPIE de ce que le parent a, descripteur de fichier dans ce cas, et fait son travail. Si un décalage est apporté au descripteur de fichier par ce parent et cet enfant, cela ne peut être que parce que le descripteur se souvient du décalage lui-même. Ai-je raison?]

Cela devrait également être clair. L'entrée du tableau de fichiers utilisateur pointe sur l'entrée de la table de fichiers (qui contient le décalage).

En d'autres termes, les appels système peuvent extraire le décalage du descripteur.


Il est important de distinguer le descripteur de fichier , qui est un petit nombre entier que le processus utilise dans ses appels en lecture et en écriture pour identifier le fichier, et la description du fichier , qui est une structure dans le noyau. Le décalage de fichier fait partie de la description du fichier. Il vit dans le noyau.

A titre d'exemple, utilisons ce programme:

#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(void)
{
    int fd;

    fd = open("output", O_CREAT|O_TRUNC|O_WRONLY, 0666);

    if(!fork()) {
        /* child */
        write(fd, "hello ", 6);
        _exit(0);
    } else {
        /* parent */
        int status;

        wait(&status);
        write(fd, "world\n", 6);
    }
}

(Tout contrôle d'erreur a été omis)

Si nous compilons ce programme, appelez-le hello et lancez-le comme ceci:

./hello

voici ce qui se passe:

Le programme ouvre le fichier de output le créant s'il n'existait pas déjà ou en le tronquant à zéro s'il existait. Le noyau crée une description de fichier (dans le noyau Linux, il s'agit d'un struct file ) et l'associe à un descripteur de fichier pour le processus appelant (le plus petit entier non négatif qui n'est pas déjà utilisé dans le tableau de descripteurs de ce processus). Le descripteur de fichier est renvoyé et assigné à fd dans le programme. Par souci d'argument, supposons que fd soit 3.

Le programme fait un fork (). Le nouveau processus enfant obtient une copie de la table de descripteurs de fichiers de son parent, mais la description du fichier n'est pas copiée. L'entrée 3 dans les tables de fichiers des deux processus pointe vers le même struct file .

Le processus parent attend pendant que le processus enfant écrit. L'écriture de l'enfant provoque le stockage de la première moitié de "hello world\n" dans le fichier et le décalage du fichier de 6. Le décalage du fichier se trouve dans le struct file !

L'enfant se ferme, le parent wait() termine et le parent écrit, en utilisant fd 3 qui est toujours associé à la même description de fichier dont le fichier offset a été mis à jour par le write() de l'enfant. La deuxième partie du message est donc stockée après la première partie, sans la remplacer comme si le parent avait un décalage de zéro, ce qui serait le cas si la description du fichier n'était pas partagée.

Enfin, le parent se ferme et le noyau voit que le struct file n'est plus utilisé et le libère.





file-descriptor