Programmation POSIX/Processus
Création
modifierpid_t fork(void);
La fonction fork crée un processus, fils du processus courant et ne différant de son père que par son PID. En cas de succès, la fonction renvoie 0 au processus fils et le PID du processus fils au processus père. En cas d'échec, elle renvoie -1 et modifie la variable errno
.
Exemple
modifier#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
switch(pid)
{
case -1:
/* cas d'erreur */
perror("fork");
break;
case 0:
/* code pour le processus fils */
printf("nooooon\n");
break;
default:
/* code pour le processus père */
printf("Je suis ton père, %d\n", pid);
}
return 0;
}
Terminaison
modifier#include <sys/types.h>
#include <sys/wait.h>
Après avoir créé un processus fils, le père doit attendre la mort de son fils, sinon ce processus restera dans l'état zombie jusqu'à la mort de son père. L'attente de la mort d'un processus est effectué soit par wait, soit par waitpid :
pid_t wait (int * statut);
wait attend la mort du prochain fils du processus courant. Si statut est différent de NULL, wait stocke le statut de ce fils au moment de sa mort.
- La macro WIFEXITED permet de tester si le fils s'est arrêté en effectuant un appel à exit et dans ce cas la macro WEXITSTATUS permet de connaitre la valeur passée en paramètre à exit.
- La macro WIFSIGNALED permet de tester si le fils s'est arrêté sur réception d'un signal et la macro WTERMSIG permet de connaitre le numéro de ce signal.
pid_t waitpid (pid_t pid, int * statut, int options);
waitpit attend la fin du fils de numéro pid. De même que pour wait, waitpid stocke le statut de ce fils au moment de sa terminaison. waitpid permet de plus de spécifier des options qui sont représentées par un binaire entre les constantes symboliques suivantes :
- WNOHANG, ne pas attendre la mort du processus ;
- WUNTRACED, remplir la variable statut aussi pour les fils bloqués.
Recouvrement
modifier#include <unistd.h>
extern char ** environ;
int execl (const char * chemin, const char * arg, ...);
int execlp (const char * fichier, const char * arg, ...);
int execle (const char * chemin, const char * arg , ..., char * const envp[]);
int execv (const char * chemin, char * const argv []);
int execvp (const char * fichier, char * const argv []);
int execve (const char * chemin, char * const argv [], char * const envp[]);
La famille des fonctions exec permet de recouvrir le processus courant par l'exécution d'un programme.
Les fonctions execl prennent comme premier argument le nom du programme a exécuter puis la liste de ses arguments terminée par NULL. Le premier argument d'un programme étant le nom de ce programme, les deux premiers arguments de execl doivent être les mêmes. Par exemple pour recouvrir un processus par /usr/bin/ls -l
:
execl("/usr/bin/ls", "/usr/bin/ls", "-l", NULL);
Les fonctions execv prennent comme premier argument le nom du programme a exécuter et comme second un tableau contenant les arguments de ce programme, la dernière case du tableau doit contenir NULL.
Les fonctions exec ne retournent pas lorsque elles réussissent, et renvoient -1 quand elles échouent. Ainsi si du code est exécuté après un appel à une fonction exec, c'est que cet appel a échoué.
Exemple
modifierCe programme créé un processus fils, puis le recouvre en tentant d'exécuter le premier argument et en lui passant comme arguments le reste de la liste des arguments.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pid;
if (argc < 2)
{
fprintf(stderr, "usage : %s programme [arguments...]\n", argv[0]);
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) // Cas d'erreur (plus assez de mémoire disponible par exemple)
{
perror("Erreur lors de la création du processus");
exit(EXIT_FAILURE);
}
else if (pid == 0) // Dans le fils
{
argv++;
execvp(argv[0], argv);
perror("execlp");
exit(EXIT_FAILURE);
}
// Dans le père
waitpid(pid, NULL, 0);
printf("\nMerci de votre confiance en %s\n", argv[1]);
return EXIT_SUCCESS;
}