En fait je voudrai mettre en place une application qui gère plusieurs processus en parallèle en C. Le problème, c'est que je ne crois pas avoir bien saisi l'utilisation du fork. Après son appel, il renvoie le PID au processus père et 0 au processus fils. Mais si mon souhait est de créer plusieurs processus fils comment ça se passe ?
Si je fais ça (En supposant que le nombre de processus à créer est spécifié dans les paramètres lors de l'exécution de l'application dans la console) :
Code :
#define Erreur(x) {perror (x);exit(errno);}
int main (int nbarg, char *tbarg[]){
int i;
for (i = 0; i < tbarg[0]; ++i){
if ((idpro = fork ()) < 0) Erreur("creation de processus" );
}
}
Est-ce que ça fonctionne ? Si oui, comment je fais pour savoir qui est qui ? (Un tableau qui se remplit avec les les pid du fork dans la boucle for?)
Si je fais ça (En supposant que le nombre de processus à créer est spécifié dans les paramètres lors de l'exécution de l'application dans la console) :
Code :
#define Erreur(x) {perror (x);exit(errno);}
int main (int nbarg, char *tbarg[]){
int i;
for (i = 0; i < tbarg[0]; ++i){
if ((idpro = fork ()) < 0) Erreur("creation de processus" );
}
}
Est-ce que ça fonctionne ?
Là non, mais pas à cause de fork. Ca compile pas parce que tu compares un char* à un int (et accessoirement selon tes options de compilation ca peut aussi te jeter parce qu'il y a pas de return dans ton main)
Mais sinon le fork aussi pose problème: après le fork, il faut que tu vérifie idpro pour sortir de la boucle si tu es dans le processus fils. Sinon, ton ordonnanceur il va se retrouver sur les genoux.
Citation :
Si oui, comment je fais pour savoir qui est qui ? (Un tableau qui se remplit avec les les pid du fork dans la boucle for?)
Différencier le père des fils c'est la valeur de retour de fork. Après pour identifier chaque fils effectivement faut que tu maintiennes une liste à la main.
Là non, mais pas à cause de fork. Ca compile pas parce que tu compares un char* à un int (et accessoirement selon tes options de compilation ca peut aussi te jeter parce qu'il y a pas de return dans ton main)
Mais sinon le fork aussi pose problème: après le fork, il faut que tu vérifie idpro pour sortir de la boucle si tu es dans le processus fils. Sinon, ton ordonnanceur il va se retrouver sur les genoux.
Ca va peut-être compiler, mais attends-toi à avoir à rebooter la machine après le programme...
Outre le fait que c'est MAL (tm) de lire tbarg[2] sans vérifier qu'il existe avec nbarg, tbarg[2] est un char*, donc casté en int, ça va te donner un nombre énorme et pas du tout son contenu... Donc tu vas te retrouver avec des millions de fils et ça se terminera en "no more process" ou équivalent (et machine quasi-bloquée). Regarde du côté de atoi().
Par ailleurs, je ne comprends pas grand-chose à ce que fait ton programme. C'est quoi le champ cote dans la structure fils, lequel n'est pas déclaré (en fait, je ne vois même pas ce que tu fermes) ?
Ca va peut-être compiler, mais attends-toi à avoir à rebooter la machine après le programme...
Outre le fait que c'est MAL (tm) de lire tbarg[2] sans vérifier qu'il existe avec nbarg, tbarg[2] est un char*, donc casté en int, ça va te donner un nombre énorme et pas du tout son contenu... Donc tu vas te retrouver avec des millions de fils et ça se terminera en "no more process" ou équivalent (et machine quasi-bloquée). Regarde du côté de atoi().
Par ailleurs, je ne comprends pas grand-chose à ce que fait ton programme. C'est quoi le champ cote dans la structure fils, lequel n'est pas déclaré (en fait, je ne vois même pas ce que tu fermes) ?
Oui c'est vrai, j'ai modifié en fait cote c'était tube.
Normalement, le programme est une sorte d'agence. Je dois passer deux fichiers dans les deux premiers paramètres (qui seront gérés par deux processus différents) et un nombre de guichets en 3è paramètre.
Le code du dessus c'était juste pour comprendre le mécanisme du fork.
En gros dans mon programme, je devrai pouvoir lancer 4 + n (correspondant au nombre de guichets passé en param) processus communiquant entre eux par des pipes.
C'est pour ça que je me demandais comme ont fait pour savoir qui est qui parce que le fork renvoie 0 quand il s'agit d'un processus fils.
En gros dans mon programme, je devrai pouvoir lancer 4 + n (correspondant au nombre de guichets passé en param) processus communiquant entre eux par des pipes.
C'est pour ça que je me demandais comme ont fait pour savoir qui est qui parce que le fork renvoie 0 quand il s'agit d'un processus fils.
Il me semble que tu n'as pas besoin de savoir qui est qui au niveau des fils pour faire un pipeline. Suffit d'utiliser pipe() dans le processus père comme il faut et de redéfinir l'entrée et la sortie standard des processus fils avec les file descriptors donnés par pipe (via dup ou dup2). Après si tu as besoin de savoir quelle fonction appeler dans le fils après fork, rien ne t'empêches d'utiliser une variable temporaire de la fonction dans laquelle tu fais le fork pour le spécifier juste avant le fork dans le père qu'elle fonction appeler.
---------------
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d.
1f u c4n wr1t3 1t t00.
Est-ce que les processus fils continuent de tourner après les if (fork() == 0) ? (Je crois que oui mais j'en suis pas sur)
Oui... Quand tu écris fork(), ce qu'il fait, c'est qu'il duplique ton programme... et à la fois le père et le fils continuent normalement.
Du coup, il y a un truc qui va potentiellement clocher dans ton programme : le premier fils, après avoir fini le traitement, va forker et se créer lui-même un propre fils si tu ne quittes pas. Il faut mettre un exit() quelque part, éventuellement à la fin de PremierFils() et SecondFils(). Mais j'ai tendance à le mettre plutôt dans le main() dans ce genre de situation, que ce soit clair. Voire dans les deux
Par ailleurs, le père va sauter les traitements, clore les deux pipes, et quitter... Je ne procède jamais comme ça, et je n'ai plus en tête les détails de la norme à ce sujet, mais je me demande si ça ne tue pas les enfants. Je me demande si tu ne devrais pas mettre un wait() pour chaque enfant avant de quitter le programme principal.
Merci pour les précisions. Je crois que j'ai compris. Au fait, après avoir testé et à l'aide de quelques affichages supplémentaires, le premier fils se crée bien son propre fils.
Dernière précision, j'ai réglé le problème de l'argument à convertir de char à int par un sscanf.
Message édité par shadow2 le 12-12-2007 à 20:00:53
Par ailleurs, le père va sauter les traitements, clore les deux pipes, et quitter... Je ne procède jamais comme ça, et je n'ai plus en tête les détails de la norme à ce sujet, mais je me demande si ça ne tue pas les enfants. Je me demande si tu ne devrais pas mettre un wait() pour chaque enfant avant de quitter le programme principal.
Je confirme, quand un processus meurt, il tue tout le sous arbre de processus. Y'a moyen de rattacher un fils à un autre processus. Mais dans ton cas tu cherches clairement pas à faire ca. Faut effectivement faire un wait, ou un waitpid si tu veux faire des trucs un peu plus tordus.
En passant, meme si le processus fils est terminé il reste en mémoire jusqu'à l'appel à wait (pour permettre de récupérer la valeur de sortie) ou la fin du processus père. Donc si tu prends beaucoup de ram dans le fils c'est pas négligeable.
Message édité par Skyfighter le 12-12-2007 à 20:38:07
---------------
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d.
1f u c4n wr1t3 1t t00.
J'ai un autre problème. Tous mes processus sont créés et font appel à des programmes extérieurs. (codés personnellement)
Le problème est que je n'arrive pas à faire communiquer ces processus par des tubes. J'ai essayé plein de trucs mai ça veut pas marcher. Donc pour faire simple, voici ma question : "Comment faire pour faire communiquer entre eux deux processus, ayant utilisé execl, par l'intermédiaire de tubes".
Et j'ai une autre interrogation sur les signaux, comment faire pour les utiliser ? J'ai l'impression que je dois stocker les pid de chacun des processus dans un tableau ou quelque chose dans le genre pour pouvoir affecter le signal au processus voulu au besoin. C'est bien ça ?
J'ai un autre problème. Tous mes processus sont créés et font appel à des programmes extérieurs. (codés personnellement)
Le problème est que je n'arrive pas à faire communiquer ces processus par des tubes. J'ai essayé plein de trucs mai ça veut pas marcher. Donc pour faire simple, voici ma question : "Comment faire pour faire communiquer entre eux deux processus, ayant utilisé execl, par l'intermédiaire de tubes".
Tu veux dire que tes fils jouent à lancer chacun un autre programme via execl et tu voudrais que les programmes en question communiquent par les tubes créés lors du fork ?
Ca me paraît tordu comme façon de procéder, je dois dire que je n'ai guère confiance à priori et je ne sais pas si c'est vraiment faisable. A ce niveau-là, je passe par socket, par envoi de message, par mémoire partagée ou par fichiers, mais conserver les tubes ne me paraît pas simple (ça marche peut-être, c'est juste que je n'ai jamais eu besoin de ça, encore une fois, ma méthode canonique pour faire communiquer des programmes distincts, c'est généralement le socket ou la mémoire partagée).
Et j'ai une autre interrogation sur les signaux, comment faire pour les utiliser ? J'ai l'impression que je dois stocker les pid de chacun des processus dans un tableau ou quelque chose dans le genre pour pouvoir affecter le signal au processus voulu au besoin. C'est bien ça ?
Quels signaux ? SIGKILL, SIGTERM, SIGFPE et autres ? Si oui, ça s'envoie à coup de kill(pid_de_destination, numéro_du_signal). Genre kill(12345, SIGTERM) va envoyer au processus 12345 un signal de terminaison, qui soit est choppé et traité par 12345, soit va terminer le programme. En gros. Après, tu peux effectivement trouver des moyens de transmettre les PIDs aux programmes externes, voire de les retrouver depuis lesdits programmes externes.
Par contre, transmettre des ordres de cette façon-là, je ne sais pas si c'est très élégant...
Tu veux dire que tes fils jouent à lancer chacun un autre programme via execl et tu voudrais que les programmes en question communiquent par les tubes créés lors du fork ?
Ca me paraît tordu comme façon de procéder, je dois dire que je n'ai guère confiance à priori et je ne sais pas si c'est vraiment faisable. A ce niveau-là, je passe par socket, par envoi de message, par mémoire partagée ou par fichiers, mais conserver les tubes ne me paraît pas simple (ça marche peut-être, c'est juste que je n'ai jamais eu besoin de ça, encore une fois, ma méthode canonique pour faire communiquer des programmes distincts, c'est généralement le socket ou la mémoire partagée).
Oui, c'est bien ça. Je crée les tubes avant les fork() qui lancent d'autres programmes et ces tubes doivent permettre aux processus de communiquer entre eux. J'ai essayé par exemple un truc comme l'affectation par un sprintf de l'un des côtés du tube dans les fork() dans un tableau qui porte le nom de ce côté(Par exemple t1LECT[2]) et en faisant en close de l'autre côté. Puis je passe ce tableau dans les paramètres de l'execl, pour pouvoir l'utiliser dans l'autre programme mais ça ne marche pas.
Quels signaux ? SIGKILL, SIGTERM, SIGFPE et autres ? Si oui, ça s'envoie à coup de kill(pid_de_destination, numéro_du_signal). Genre kill(12345, SIGTERM) va envoyer au processus 12345 un signal de terminaison, qui soit est choppé et traité par 12345, soit va terminer le programme. En gros. Après, tu peux effectivement trouver des moyens de transmettre les PIDs aux programmes externes, voire de les retrouver depuis lesdits programmes externes.
Par contre, transmettre des ordres de cette façon-là, je ne sais pas si c'est très élégant...
En fait, je dois utiliser les signaux de façon à prévenir les processus qui vont lire les tubes qu'ils peuvent effectivement lire dans ces tubes sans complication. (Mais je ne sais pas quel signal utililser pour ce genre de chose)
Tu veux dire que tes fils jouent à lancer chacun un autre programme via execl et tu voudrais que les programmes en question communiquent par les tubes créés lors du fork ?
Ca me paraît tordu comme façon de procéder, je dois dire que je n'ai guère confiance à priori et je ne sais pas si c'est vraiment faisable. A ce niveau-là, je passe par socket, par envoi de message, par mémoire partagée ou par fichiers, mais conserver les tubes ne me paraît pas simple (ça marche peut-être, c'est juste que je n'ai jamais eu besoin de ça, encore une fois, ma méthode canonique pour faire communiquer des programmes distincts, c'est généralement le socket ou la mémoire partagée).
C'est l'exemple que j'avais donné plus haut en fait. Un shell passe son temps à faire ce genre de manip pour gérer les pipes. Faut changer l'entrée et la sortie standard du processus avant de faire un execl (via dup ou dup2 je sais plus). Comme ca suffit que le processus utilise l'entrée et la sortie standard pour que les informations passent dans un pipe. Le seul truc c'est que ca suppose que le processus père de toute la chaine de pipe ferme bien le pipe après le fork. Sinon on atteint assez vite la limite du système en nombre de descripteurs de fichiers (enfin vite... c'est relatif au sujet je dirais).
---------------
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d.
1f u c4n wr1t3 1t t00.
Skyfighter : merci pour les détails, le pire, c'est que j'en avais besoin mais que j'ignorais comment faire ça Et évidemment, pas un informaticien dans mon entourage pour savoir ça... Bon, je vais faire des tests (j'ai des programmes de filtrage/traitemet qui prennent leurs infos sur des file descriptors, et sortent les résultats sur des file descriptors, mais je ne savais pas comment les brancher les uns sur les autres par fork, je devrais pouvoir m'en sortir comme ça).
En fait, je dois utiliser les signaux de façon à prévenir les processus qui vont lire les tubes qu'ils peuvent effectivement lire dans ces tubes sans complication. (Mais je ne sais pas quel signal utililser pour ce genre de chose)
Je ne pense pas que tu aies besoin de signaux pour ça...
Si tu n'as pas besoin de faire de calculs en attendant que quelque chose arrive sur le tube, tu peux simplement faire une lecture, le programme se mettra en pause jusqu'à ce que quelque chose arrive sur le tube. Sinon, tu as des fonctions de lectures non bloquantes qui te disent si le tube est vide ou non (ou si tu n'en as pas, tu peux toujours forker maintenant que tu es spécialiste).
Skyfighter : merci pour les détails, le pire, c'est que j'en avais besoin mais que j'ignorais comment faire ça Et évidemment, pas un informaticien dans mon entourage pour savoir ça... Bon, je vais faire des tests (j'ai des programmes de filtrage/traitemet qui prennent leurs infos sur des file descriptors, et sortent les résultats sur des file descriptors, mais je ne savais pas comment les brancher les uns sur les autres par fork, je devrais pouvoir m'en sortir comme ça).
C'est le principe de base. De mémoire y'a une méthode qui permet de dépasser la limite système sur les fd. Si ca t'intéresse, faudrait aller voir du côté du code source de zsh (ou de bash éventuellement, si tu as une boite d'aspirines à portée de main). PS: et avec un bon vieux isatty() tu peux détecter si l'entrée est un tty ou un fichier / pipe, ce qui permet de détecter la nécessité d'un affichage de mode interractif
Message édité par Skyfighter le 10-01-2008 à 18:07:14
---------------
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d.
1f u c4n wr1t3 1t t00.
J'ai fait quelques tests qui ont fonctionné sur deux-trois processus et ça avait l'air de marcher avec dup2 pour mes tubes mais dès que j'essaie d'appliquer ça à mon programme ça ne marche pas.
Voici le code :
Code :
#define Erreur(x) {perror (x);exit(errno);}
void Dup2(int fd1, int fd2){
printf("Dup2 en cours..." );
if (dup2(fd1, fd2) == -1){
Erreur("Erreur de redirection entre l'E/S du tube vers stdin/stdout\n" );
exit(EXIT_FAILURE);
}
printf("reussi\n" );
}
int main (int nbarg, char *tbarg[]){
int cpt, i, s, idPro;
int nbGuichet = 2;
int Tfils1_fils2[2];
int Tfils2_fils3[2];
int Tfils3_fils1[2];
pipe(Tfils1_fils2);
pipe(Tfils2_fils3);
pipe(Tfils3_fils1);
idPro = fork();
if (idPro < 0){
Erreur("timer" );
}
if (idPro == 0){
if (execl("./timer", "timer", NULL) < 0)
Erreur("Chargement timer" )
exit(0);
}
idPro = fork();
if (idPro < 0){
Erreur("fils1" );
}
if (idPro == 0){
close(Tfils1_fils2[0]);
Dup2(Tfils1_fils2[1], STDOUT_FILENO);
close(Tfils3_fils1[1]);
Dup2(Tfils3_fils1[0], STDIN_FILENO);
if (execl("./fils1", "fils1", NULL) < 0)
Erreur("Chargement fils1" )
exit(0);
}
for (cpt = 0; cpt < nbGuichet; ++cpt){
idPro = fork();
if (idPro < 0){
Erreur("fils2" );
}
if (idPro == 0){
close(Tfils2_fils3[0]);
Dup2(Tfils2_fils3[1], STDOUT_FILENO);
close(Tfils1_fils2[1]);
Dup2(Tfils1_fils2[0], STDIN_FILENO);
if (execl("./fils2", "fils2", NULL) < 0)
Erreur("Chargement fils2" )
exit(0);
}
}
idPro = fork();
if (idPro < 0){
Erreur("fils3" );
}
if (idPro == 0){
close(Tfils3_fils1[0]);
Dup2(Tfils3_fils1[1], STDOUT_FILENO);
close(Tfils2_fils3[1]);
Dup2(Tfils2_fils3[0], STDIN_FILENO);
if (execl("./fils3", "fils3", NULL) < 0)
Erreur("Chargement fils3" )
exit(0);
}
else{
int j;
for (j = 0; j < 5; ++j){
printf("Je suis le père\n" );
}
i = wait(&s);
i = wait(&s);
i = wait(&s);
i = wait(&s);
i = wait(&s);
exit(EXIT_SUCCESS);
}
}
Le code compile sans souci mais voilà, à l'exécution, quand il passe dans la fonction Dup2 et n'affiche que : "Dup2 en cours..." dans les processus qui vont utiliser les tubes.
Par contre, les affichages du père et du timer fonctionnent.
Comment puis-je régler ce problème ?
Merci d'avance.
Message édité par shadow2 le 12-01-2008 à 19:22:05
---------------
Linux peut être sexy, le preuve :
shadow2@shadow2-linux:~$ who | grep -i blonde | talk; cd ~; wine; talk; touch; unzip; touch; strip; gasp; finger; mount; fsck; more; yes; gasp; unmount; make clean; sleep;
Hum... en l'état ça ne peux pas marcher: tu essayes d'utiliser le même pipe pour tous les guichets et ça risque de créer de gros problèmes de concurence entre les processus. Enfin ça dépend comment tu écris dans le pipe en fait. Si tu passes par write ça a des chances de marcher étant donné que c'est un syscall. Mais si tu utilises des fonctions d'écrture bufferisées c'est mort (tu pourrais avoir des processus qui écrivent en plein millieu de ce qu'écrivent les autres pendant qu'ils remplissent leur buffer). Remarque cependant que dans les deux cas c'est gorre.
Je suis en train de bidouiller un peu ton code pour avoir des sorties sur la sortie d'erreur et comprendre ce qui se passe.
Justement l'idée est de gérer cette concurrence par des signaux(Un signal qui indique aux processus quand il peuvent lire/ecrire) même si pour l'instant, j'ai pas encore touché à ça faute de compréhension suffisante du mécanisme.
Sinon oui, je compte utiliser des read/write pour les tubes.
Message édité par shadow2 le 12-01-2008 à 19:25:04
---------------
Linux peut être sexy, le preuve :
shadow2@shadow2-linux:~$ who | grep -i blonde | talk; cd ~; wine; talk; touch; unzip; touch; strip; gasp; finger; mount; fsck; more; yes; gasp; unmount; make clean; sleep;
Apparemment déjà y'a un problème au niveau de wait qui attend... pas J'en ai rajouté une petite dizaine le processus père termine quand même. Il doit falloir lui filer une option pour qu'il reste bloquant ou un truc dans le genre...
---------------
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d.
1f u c4n wr1t3 1t t00.
write(2, "Erreur de redirection entre l'E/S du tube vers stdin/stdout\n",
60);
exit(EXIT_FAILURE);
}
write(2, "reussi\n" , 7);
}
int main (int nbarg, char *tbarg[])
{
int cpt, i, s;
int pid1, pid2, pid3;
int nbProc = 2;
int Tfils1_fils2[2];
int Tfils2_fils3[2];
int Tfils3_fils1[2];
pipe(Tfils1_fils2);
pipe(Tfils2_fils3);
pipe(Tfils3_fils1);
/*
idPro = fork();
if (idPro < 0)
Erreur("timer" );
if (idPro == 0)
{
if (execl("./timer", "timer", NULL) < 0)
{
Erreur("Chargement timer" );
exit(0);
}
}
*/
pid1 = fork();
if (pid1 < 0)
Erreur("fils1" );
if (pid1 == 0)
{
Dup2(Tfils1_fils2[1], STDOUT_FILENO);
Dup2(Tfils3_fils1[0], STDIN_FILENO);
close(Tfils1_fils2[0]);
close(Tfils1_fils2[1]);
close(Tfils2_fils3[0]);
close(Tfils2_fils3[1]);
close(Tfils3_fils1[0]);
close(Tfils3_fils1[1]);
if (execl("/bin/echo", "fils1", "plonk", NULL) < 0)
{
Erreur("Chargement fils1" );
exit(0);
}
}
for (cpt = 0; cpt < nbGuichet; ++cpt)
{
pid2 = fork();
if (pid2 < 0)
Erreur("fils2" );
if (pid2 == 0)
{
Dup2(Tfils2_fils3[1], STDOUT_FILENO);
Dup2(Tfils1_fils2[0], STDIN_FILENO);
close(Tfils1_fils2[0]);
close(Tfils1_fils2[1]);
close(Tfils2_fils3[0]);
close(Tfils2_fils3[1]);
close(Tfils3_fils1[0]);
close(Tfils3_fils1[1]);
if (execl("/bin/cat", "fils2", NULL) < 0)
{
Erreur("Chargement fils2" );
exit(0);
}
}
}
pid3 = fork();
if (pid3 < 0)
Erreur("fils3" );
if (pid3 == 0)
{
Dup2(Tfils2_fils3[1], STDOUT_FILENO);
Dup2(Tfils2_fils3[0], STDIN_FILENO);
close(Tfils1_fils2[0]);
close(Tfils1_fils2[1]);
close(Tfils2_fils3[0]);
close(Tfils2_fils3[1]);
close(Tfils3_fils1[0]);
close(Tfils3_fils1[1]);
if (execl("/bin/cat", "fils3", NULL) < 0)
{
Erreur("Chargement fils3" );
exit(0);
}
}
else
{
close(Tfils1_fils2[0]);
close(Tfils1_fils2[1]);
close(Tfils2_fils3[0]);
close(Tfils2_fils3[1]);
close(Tfils3_fils1[0]);
close(Tfils3_fils1[1]);
int j;
for (j = 0; j < 5; ++j)
printf("Je suis le pere\n" );
i = waitpid(pid1, NULL, 0);
i = waitpid(pid2, NULL, 0);
i = waitpid(pid3, NULL, 0);
exit(EXIT_SUCCESS);
}
}
Le code comme ça chez moi passe. Par rapport au tiens y'a pas un grosse différence. J'ai remplacé les wait par des waitpid sur un pid précis (ce qui chez moi à l'air de mieux marcher mais je me suis rendu compte après coup que je forkais les fils 2 et 3 dans le premier fils donc si ca se trouve wait marche très bien). J'ai fermé tous les pipes à dans les fils et le père (respectivement avant les execl et avant les wait) pour pas que les processus attendent indéfiniment des infos à partir du père ou d'un des fils (et puis j'ai bidouillé à partir de cat et echo vu que j'avais pas tes binaires).
Je pense qu'en fait ton problème était surtout de l'affichage. Tu faisais des printf après un dup2 sur la sortie standard... Là j'ai tout passé en write sur la sortie d'erreur
Message édité par Skyfighter le 12-01-2008 à 20:20:59
---------------
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d.
1f u c4n wr1t3 1t t00.
Au fait, en théorie, si je mets en application ce code et que chacun des fils fait juste un read et un write sur les STDIN/STDOUT, les traces d'exécution de ces read/write ne sont pas apparentes à l'écran vu que les trois processus forment une sorte de boucle, c'est bien ça ?
Au fait, en théorie, si je mets en application ce code et que chacun des fils fait juste un read et un write sur les STDIN/STDOUT, les traces d'exécution de ces read/write ne sont pas apparentes à l'écran vu que les trois processus forment une sorte de boucle, c'est bien ça ?
Tant que tu parles de l'entrée et de la sortie standard oui.
Si tu veux un affichage, faut passer par la sortie d'erreur ou alors un fichier.
OK et toujours uniquement par des write ? (sprintf avec redirection vers un fichier ne marcherait pas ?)
Le problème de printf c'est que ca peut pas etre considéré comme une opération atomique. Donc tu risques d'avoir des choses très bizarres em sortie.
Ce que tu peux faire éventuellement c'est un fichier de log par processus. Ou alors déléguer tout le travail d'écriture à un processus mais c'est reculer pour mieux sauter: tu seras obliger de gérer la concurence au niveau des communications (je sais même pas si c'est faisable à partir de signaux... faudrait peut être même passer par des sockets)
Ca revient à un problème d'accès concurrenciel à une ressource. Du coup, tu dois pouvoir régler ça avec des signaux, façon token ring ou dérivé.
Ah oui tiens... du coup tant qu'avant de libérer le token le processus fait un fflush ca doit passer en bufferisé sur tous les processus... Bon en fait j'ai rien dit ton exo est faisable
Citation :
M'enfin, je trouve ça des plus bizarres...
Pareil du coup... quel est l'intérêt de forker et de faire des pipes si on force l'exécution des processus à être séquentielle en les synchronisant par envoi de message
---------------
1f u c4n r34d th1s u r34lly n33d t0 g37 l41d.
1f u c4n wr1t3 1t t00.
Je ne sais pas trop? En théorie, il y a quelques opérations qui sont feront sans lire ou écrire dans les tubes dans les processus fils mais bon c'est clair que l'intérêt est assez limité.
Au fait, si je fais des fflush, les printf font passer du coup ? Parce que ça vient de là les trucs bizarres en sortie, non ?
Au fait, si je fais des fflush, les printf font passer du coup ? Parce que ça vient de là les trucs bizarres en sortie, non ?
La seule chose que fflush te garantit c'est qu'en sortie de la fonction les buffers de sortie auront été écrits et vidés. Ca ne règle absolument pas les problèmes de concurence entre les processus. Ca te garanti juste que tout aura été écrit. Mais si tu synchronises les processus et que tu déclenches le suivant suite à un fflush là normalement c'est bon.
La seule chose que fflush te garantit c'est qu'en sortie de la fonction les buffers de sortie auront été écrits et vidés. Ca ne règle absolument pas les problèmes de concurence entre les processus. Ca te garanti juste que tout aura été écrit. Mais si tu synchronises les processus et que tu déclenches le suivant suite à un fflush là normalement c'est bon.
OK merci encore une fois pour ton aide.
J'ai plus qu'à bien comprendre les signaux. Le truc c'est de créer une fonction qui sera déclenchée pour un processus donné (par son pid) avec le délenchement d'un signal comme kill par exemple ?
Mais pour kill(pid, le signal choisi), comment on choisit le signal ? (Les SIGUSR1, SIGUSR2...)
J'ai plus qu'à bien comprendre les signaux. Le truc c'est de créer une fonction qui sera déclenchée pour un processus donné (par son pid) avec le délenchement d'un signal comme kill par exemple ?
Mais pour kill(pid, le signal choisi), comment on choisit le signal ? (Les SIGUSR1, SIGUSR2...)
Attends déjà qu'on soit bien d'accord. Kill c'est la fonction d'envoi de signal. Donc pour envoyer un signal tu fais kill(pid, signal).
L'argument signal, c'est un signal. SIGUSR1 et SIGUSR2 sont réservés à l'utilisateur, les autres normalement au système.
Tiens, je me pose une question en relisant ça. Je me souvenais que Sigkill n'était pas détournable (logique) mais je pensais que Sigstop (c'est bien kill -15 ?) pouvait l'être...
Il se passe quoi suite à un Sigstop ? J'ai l'impression que certains programmes font des trucs avant de quitter, d'ailleurs certains ne quittent pas... On peut provoquer quelque chose, genre via un atexit() ?
Tiens, je me pose une question en relisant ça. Je me souvenais que Sigkill n'était pas détournable (logique) mais je pensais que Sigstop (c'est bien kill -15 ?) pouvait l'être...
Il se passe quoi suite à un Sigstop ? J'ai l'impression que certains programmes font des trucs avant de quitter, d'ailleurs certains ne quittent pas... On peut provoquer quelque chose, genre via un atexit() ?
http://www.traduc.org/~gleu/ykerb/ch12.html Ca devrait répondre à ta question. Mais en résumé SIGTERM et SIGSTOP peuvent être catchés, mais le processus est détruit après exécution de la fonction associée au catch (là où je me pose des questions, c'est comment ca se passe quand on a une bibliothèque qui définit un truc exécuter au déchargement...).
http://www.traduc.org/~gleu/ykerb/ch12.html Ca devrait répondre à ta question. Mais en résumé SIGTERM et SIGSTOP peuvent être catchés, mais le processus est détruit après exécution de la fonction associée au catch (là où je me pose des questions, c'est comment ca se passe quand on a une bibliothèque qui définit un truc exécuter au déchargement...).
Oui, moi aussi... A voir aussi comment ça se passe si la fonction prend trop de temps pour se terminer (remarque, ça explique pourquoi certains programmes résistent au Sigkill )
Mais en fait, c'est moi qui me suis mélangé les pinceaux... Sigkill et Sigstop ne peuvent pas être catchés avec la méthode du dessus, mais fermer un programme, ou -15, c'est Sigterm, qui lui est catchable (ce qui correspond à ce dont je me souvenais).