Répondre à la discussion
Affichage des résultats 1 à 6 sur 6

Fontion Fork()



  1. #1
    Silver68

    Smile Fontion Fork()


    ------

    Bonjour ,
    J'ai un code dont je ne comprends pas le fonctionnement

    l'exécution de celui ci donne:

    Fils voit 1
    Fils voit 2
    Fils voit 3
    Fils voit 99
    Le fils a terminé
    $
    Pourquoi le message « Fils voit 99 » s'affiche til ?

    j'espère que quelqu'un saura m'expliquer le fonctionement


    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <errno.h>

    #define PERM_FILE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

    static int *getaddr(void) {
    key_t key;
    int shmid, *p;
    p=NULL;
    (void)close(open("shmseg", O_WRONLY | O_CREAT, 0));
    if ((key = ftok ("shmseg",1)) == 1)
    {
    printf("Échec de ftok\n");
    return(NULL);
    }
    if ((shmid=shmget(key,sizeof(int) ,IPC_CREAT | PERM_FILE))==1)
    {
    perror("Échec de ftok\n");
    return(NULL);
    }
    if ((p=shmat(shmid,NULL,0))==((vo id *)1))
    {
    perror("Échec de shmat");
    return(NULL);
    }
    return(p);
    }

    int main(void) {
    pid_t pid;
    if ((pid=fork()) == 0) {
    int *p,prev=0;
    if ((p=getaddr()) == NULL) {
    printf("Échec de getaddr\n");
    exit(EXIT_FAILURE);
    }
    while (*p != 99)
    if (prev != *p) {
    printf("Fils voit %d\n",*p);
    prev = *p;
    }
    printf("Le fils a terminé\n");
    } else {
    int *p;
    if ((p=getaddr()) == NULL) {
    printf("Échec de getaddr\n");
    exit(EXIT_FAILURE);
    }
    for (*p = 1; *p < 4; (*p)++)
    sleep(1);
    *p = 99;
    }
    exit(EXIT_SUCCESS);
    }

    -----

  2. Publicité
  3. #2
    Towl

    Re : Fontion Fork()

    Tiens marrant, j'aurais pas cru que la probabilité d'afficher 99 soit si grande, mais c'est le genre de truc qui amuse toujours avec les processus / thread

    Une petite analyse rapide du code montre que le seul moment ou tu affiches p, c'est dans ce bloc :
    Code:
    while (*p != 99)
    	if (prev != *p) 
    	{
    		printf("Fils voit %d\n",*p);
    		prev = *p;
    	}
    Tandis que la seule partie ou tu le modifies c'est celle ci :
    Code:
    for (*p = 1; *p < 4; (*p)++)
    	sleep(1);
    *p = 99;
    Maintenant, il y a un truc à ce rappeler : le scheduler est ton ennemi Le scheduler dispose du pouvoir de dire à un processus d'executer du code ou de donner la main à un autre à tout moment (seule une instruction assembleur ne peut pas être stoppée). Or ton programme a deux processus, sans mécanisme de verrouillage (semaphore ou autre). Donc le code du fils peut etre stoppé à tout moment, y compris entre le test de *p != 99 et le printf.

    Ce qui peut donner un code ressemblant à cela vu de la machine (écrit en C, en zappant les changement de contexte et autre) :
    Code:
    // Execution du code du fils
    while (*p != 99)
    	if (prev != *p) 
    	{
    // Boum le vilain scheduler estime que le fils à trop travaillé 
    // Execution du code du père
    *p = 99;
    exit(EXIT_SUCCESS);
    // Le père vient de se finir. Le vilain scheduler redonne la main au fils
    // Ohh on lit p, pas de bol, le père vient de le changer à 99....
    printf("Fils voit %d\n",*p);
    		prev = *p;
    Et voila le genre de truc que le grand méchant scheduler est capable de faire. Il faut donc toujours protéger son code avec des verrous pour l'empecher de nous nuire
    The only limiting factor of the Linux operating system, is his user. - Linus Torvalds

  4. #3
    Silver68

    Re : Fontion Fork()

    Citation Envoyé par Towl Voir le message
    Tiens marrant, j'aurais pas cru que la probabilité d'afficher 99 soit si grande, mais c'est le genre de truc qui amuse toujours avec les processus / thread

    Une petite analyse rapide du code montre que le seul moment ou tu affiches p, c'est dans ce bloc :
    Code:
    while (*p != 99)
    	if (prev != *p) 
    	{
    		printf("Fils voit %d\n",*p);
    		prev = *p;
    	}
    Tandis que la seule partie ou tu le modifies c'est celle ci :
    Code:
    for (*p = 1; *p < 4; (*p)++)
    	sleep(1);
    *p = 99;
    Maintenant, il y a un truc à ce rappeler : le scheduler est ton ennemi Le scheduler dispose du pouvoir de dire à un processus d'executer du code ou de donner la main à un autre à tout moment (seule une instruction assembleur ne peut pas être stoppée). Or ton programme a deux processus, sans mécanisme de verrouillage (semaphore ou autre). Donc le code du fils peut etre stoppé à tout moment, y compris entre le test de *p != 99 et le printf.

    Ce qui peut donner un code ressemblant à cela vu de la machine (écrit en C, en zappant les changement de contexte et autre) :
    Code:
    // Execution du code du fils
    while (*p != 99)
    	if (prev != *p) 
    	{
    // Boum le vilain scheduler estime que le fils à trop travaillé 
    // Execution du code du père
    *p = 99;
    exit(EXIT_SUCCESS);
    // Le père vient de se finir. Le vilain scheduler redonne la main au fils
    // Ohh on lit p, pas de bol, le père vient de le changer à 99....
    printf("Fils voit %d\n",*p);
    		prev = *p;
    Et voila le genre de truc que le grand méchant scheduler est capable de faire. Il faut donc toujours protéger son code avec des verrous pour l'empecher de nous nuire
    Ah c'est vicieux j'aurais jamais deviné tout seul ,moi je pensais que le sleep(1) introduit une desynchronisation entre le processus pere et le processus fils.
    En effet a l'éxecution du programme on n'obtient pas la ligne:
    Fils voit 99
    si jai bien compris le resulat sera different ca depend de la machine.
    Merci beaucoup

  5. #4
    Towl

    Re : Fontion Fork()

    En fait, ton sleep ne fait qu'endormir le père. Mais tu maintient une sorte de synchronisation entre le père et le fils avec une attente active (ton while (*p != 99)).

    Avec une telle attente active, ton processus fils va consommer énormément de temps CPU, contrairement à son père qui dort 1 seconde par-ci par-là. Certains scheduler vont donc avoir tendance à privilégier les instructions du père sur celles du fils, partant du principe qu'il n'a pas souvent eu la main.

    Après le fait d'avoir un 99 ou non va dépendre non pas du programme, ni de la machine, mais de tout un tas de facteurs, comme le nombre de processus, le temps alloué a chacun d'eux, la charge processeur, ....


    Petite explication (pour le fun ) sur la proba si forte d'avoir un 99 d'affiché :

    Si l'on regarde au niveau assembleur ce que l'on a : (asm fait de tête, flemme de vérifier / compiler ... )
    Père :
    Code:
    	cmp ecx, 4
    	je fin_bcl
    	inc ecx
    	mov [eax], ecx
    	call sleep
    fin_bcl:
    	mov [eax], 99
    	ret
    Fils :
    Code:
    deb_while:
    	cmp [eax], 99
    	je fin_while
    	cmp ecx, ebx
    	je deb_while
    	push esi
    	push [eax]
    	call printf
    	mov ebx, [eax]
    	jmp deb_while
    fin_while:
    	ret
    Comme tu peux le voir (ou pas ), pour le père, entre le dernier sleep et la mise à 99 de p, il n'y a pas d'instruction intermédiaire. Dès qu'il sort du sleep, le père mets p à 99, sans pouvoir être interrompu.
    Le fils test la valeur de p en première ligne (cmp [eax], 99) mais ne l'utilise que 6 instruction après (push [eax]). Le changement de main peut avoir lieu à n'importe quel moment entre ces 6 instructions, ce qui n'est pas anodin. Si en plus tu rajoutes le fait que tu es en attente active, donc que ton fils passe son temps à executer les instructions du while (comprise entre deb_while et fin_while), tu peux considérer que ton fils ne fait que 9 instructions au total. Ton processus à donc 6 chances sur 9 d'etre interrompu où il ne le faut pas.
    The only limiting factor of the Linux operating system, is his user. - Linus Torvalds

  6. A voir en vidéo sur Futura
  7. #5
    Silver68

    Re : Fontion Fork()

    Citation Envoyé par Towl Voir le message
    En fait, ton sleep ne fait qu'endormir le père. Mais tu maintient une sorte de synchronisation entre le père et le fils avec une attente active (ton while (*p != 99)).

    Avec une telle attente active, ton processus fils va consommer énormément de temps CPU, contrairement à son père qui dort 1 seconde par-ci par-là. Certains scheduler vont donc avoir tendance à privilégier les instructions du père sur celles du fils, partant du principe qu'il n'a pas souvent eu la main.

    Après le fait d'avoir un 99 ou non va dépendre non pas du programme, ni de la machine, mais de tout un tas de facteurs, comme le nombre de processus, le temps alloué a chacun d'eux, la charge processeur, ....


    Petite explication (pour le fun ) sur la proba si forte d'avoir un 99 d'affiché :

    Si l'on regarde au niveau assembleur ce que l'on a : (asm fait de tête, flemme de vérifier / compiler ... )
    Père :
    Code:
    	cmp ecx, 4
    	je fin_bcl
    	inc ecx
    	mov [eax], ecx
    	call sleep
    fin_bcl:
    	mov [eax], 99
    	ret
    Fils :
    Code:
    deb_while:
    	cmp [eax], 99
    	je fin_while
    	cmp ecx, ebx
    	je deb_while
    	push esi
    	push [eax]
    	call printf
    	mov ebx, [eax]
    	jmp deb_while
    fin_while:
    	ret
    Comme tu peux le voir (ou pas ), pour le père, entre le dernier sleep et la mise à 99 de p, il n'y a pas d'instruction intermédiaire. Dès qu'il sort du sleep, le père mets p à 99, sans pouvoir être interrompu.
    Le fils test la valeur de p en première ligne (cmp [eax], 99) mais ne l'utilise que 6 instruction après (push [eax]). Le changement de main peut avoir lieu à n'importe quel moment entre ces 6 instructions, ce qui n'est pas anodin. Si en plus tu rajoutes le fait que tu es en attente active, donc que ton fils passe son temps à executer les instructions du while (comprise entre deb_while et fin_while), tu peux considérer que ton fils ne fait que 9 instructions au total. Ton processus à donc 6 chances sur 9 d'etre interrompu où il ne le faut pas.
    OK maintenant c'est compris,je vous remercie pour ces explications pertinentes.

  8. #6
    Towl

    Re : Fontion Fork()

    Saleté de limitation à 5min pour l'édition

    D'ailleurs si on regarde bien, tu as aussi un autre problème : ton programme peut afficher "1, 2", voire "1, 2, 99"
    En effet, ton fils peut etre interrompu entre l'affichage (push [eax]) et l'affectation à prev (mov ebx, [eax])

    Ce qui peut donner un truc du genre :
    Code:
    // Fils
    printf("Fils voit 2");
    // Père
    *p = 3
    // fils
    prev = *p (=3)
    Donc ici ton prev vaudra 3 sans jamais l'avoir affiché

    Et oui, je t'avais dit que le scheduler était ton ennemi
    The only limiting factor of the Linux operating system, is his user. - Linus Torvalds

  9. Publicité

Discussions similaires

  1. Etude d'une fontion
    Par lisa741 dans le forum Mathématiques du supérieur
    Réponses: 12
    Dernier message: 11/11/2008, 17h53
  2. Fonction Fork
    Par NAGHAM dans le forum Logiciel - Software - Open Source
    Réponses: 9
    Dernier message: 24/05/2008, 15h52
  3. fontion; dérivée
    Par sassou972 dans le forum Mathématiques du collège et du lycée
    Réponses: 2
    Dernier message: 17/04/2008, 12h29
  4. fontion ln
    Par lapin rose dans le forum Mathématiques du supérieur
    Réponses: 6
    Dernier message: 25/01/2006, 15h44
  5. Fontion IR ---->IR
    Par integra11 dans le forum Mathématiques du supérieur
    Réponses: 25
    Dernier message: 21/02/2005, 17h04
Découvrez nos comparatifs produits sur l'informatique et les technologies.