[C] Exécution aléatoire d'un programme

a marqué ce sujet comme résolu.

Bonjour,

Le programme suivant s’exécute de manière aléatoire. Soit il produit le premier résultat, soit le deuxième. Pourquoi l’un et l’autre peuvent-ils arriver ?

df                   f

Le code :

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    int ret_pid = fork();
    
    if (ret_pid == -1)
    {
        perror ("Erreur lors du fork: ");
        return EXIT_FAILURE;
    }

    if (ret_pid == 0)                           /* retour 0 -> processus fils */
    {
        // (pid : , ppid : )
        printf ("Je suis le fils (pid : %d, ppid : %d).\n", getpid(), getppid());
    }
    else                                        /* autre retour -> processus père */
    {
        // (pid : , ppid : )
        printf ("Je suis le père (pid : %d, ppid : %d).\n", getpid(), getppid());
    }

    return EXIT_SUCCESS;
}

Le problème, c’est que dans la première situation, getppid ne revoie pas le vrai pid du père….

Le comportement est parfaitement normal.

Le retour d’un fork() est en effet aléatoire. Le système d’exploitation va exécuter l’un ou l’autre en premier et tu n’as pas moyen de prédire lequel. C’est attendu et ne doit pas poser de problèmes.

Après tout, ce sont des processus séparés maintenant. Ils doivent mener leur vie.

Dans le premier cas le ppid() n’est en effet pas celui du père qui lui a donné naissance. Car manifestement, étant exécuté en premier, il est déjà mort (RIP). Par conséquent un autre processus parent prend le relais pour devenir le père du processus fils orphelin.

Si tu ajoutes une instruction wait() dans le code du père, pour qu’il attende que le fils meurt pour récupérer son status, tu tomberas toujours dans le second cas.

+3 -0

Merci ! :)

Pourquoi il me dit que wait n’est pas défini ?

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    int ret_pid = fork();
    
    if (ret_pid == -1)
    {
        perror ("Erreur lors du fork: ");
        return EXIT_FAILURE;
    }

    if (ret_pid == 0)                           /* retour 0 -> processus fils */
    {
        // (pid : , ppid : )
        printf ("Je suis le fils (pid : %d, ppid : %d).\n", getpid(), getppid());
    }
    else                                        /* autre retour -> processus père */
    {
        // (pid : , ppid : )
        printf ("Je suis le père (pid : %d, ppid : %d).\n", getpid(), getppid());
        wait();
    }

    return EXIT_SUCCESS;
}

_test.c:26:9: warning: implicit declaration of function ‘wait’ [-Wimplicit-function-declaration]

Merci, c’est corrigé :)

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <wait.h>

int main(void)
{
    int ret_pid = fork();
    
    if (ret_pid == -1)
    {
        perror ("Erreur lors du fork: ");
        return EXIT_FAILURE;
    }

    if (ret_pid == 0)                           /* retour 0 -> processus fils */
    {
        // (pid : , ppid : )
        printf ("Je suis le fils (pid : %d, ppid : %d).\n", getpid(), getppid());
    }
    else                                        /* autre retour -> processus père */
    {
        // (pid : , ppid : )
        printf ("Je suis le père (pid : %d, ppid : %d).\n", getpid(), getppid());
        wait(NULL);
    }

    return EXIT_SUCCESS;
}
+0 -0

Le retour d’un fork() est en effet aléatoire. Le système d’exploitation va exécuter l’un ou l’autre en premier et tu n’as pas moyen de prédire lequel. C’est attendu et ne doit pas poser de problèmes.

J’ai l’impression d’avoir trouvé un contre-exemple.
Dans le code ci-dessous, pourquoi le message du père ligne 27 s’exécute toujours avant le message du fils (ligne 22) alors qu’il est appelé avant la fonction wait ?

Si le programme exécute aléatoirement l’un ou l’autre, on s’attend à ce que que les messages pères/fils (resp. lignes 27 et 22) puissent s’intervertir.

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>


int main(void)
{
    int ret_pid = fork();


    if (ret_pid == -1)
    {
        perror("Erreur lors du fork : ");
        return EXIT_FAILURE;
    }


    if (ret_pid == 0) //retour 0 -> processus fils
    {
        printf("Je suis le fils (pid: %d, ppid: %d).\n", getpid(), getppid());
    }
    else
    {
        int statut_fils;
        printf("Je suis le père (pid: %d, ppid: %d).\n", getpid(), getppid());
        
        wait(&statut_fils);

        if (WIFEXITED(statut_fils))
        {
            printf("Code de retour du fils: %d.\n", WEXITSTATUS(statut_fils));
        }
        else
        {
            printf("Il se passe quoi ici ?\n");
        }
    }


    return EXIT_SUCCESS;
}

Tu ne démontres rien du tout.

L’API POSIX (d’où vient le fork) spécifie que l’ordre d’exécution après cette fonction est indéfinie. Tout comportement est donc valide : père avant le fils, fils avant le père, les deux en même temps (cas d’un système multiprocesseur). Tu ne peux pas fonder ta logique applicative donc sur un ordre particulier, tu dois partir du principe que tout cas est possible à tout moment.

Mais cela ne signifie pas que l’ordre est toujours indéterminé. Sous Linux il semble même possible de configurer un ordre particulier dans le système. Et l’ordre peut dépendre de certaines variables qui sont dans certain cas toujours réunis.

Bref, avoir un bout de code qui a toujours un ordre précis comme ici n’est pas un contre exemple. Techniquement si sous Linux c’était toujours le père qui était exécuté le premier, ce serait conforme à la norme POSIX quand même.

Et pour info j’ai le même comportement avec ou sans wait, ce dernier n’a aucune influence sur l’ordre d’exécution.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte