OVH Cloud OVH Cloud

synchronisation entre process père et fils

5 réponses
Avatar
Petit Grasshopper
Bonjour,

J'ai besoin de réaliser un programme qui fait ceci:
- initialisation
- fork()
- le père s'endort
- le fils fait un certain boulot, prévient le père puis s'endort
- le père fait sa part de boulot et meurt
- le fils continue à dormir jusqu'à ce qu'on le réveille

J'ai fait ça comme ça (en simplifiant) :

newpid = fork();
if (newpid == 0) {
/* fils */
boulot1();
kill(getppid(), SIGUSR1);
pause();
}
else {
/* père */
pause();
boulot2();
exit(0);
}

Ça marche. Mais en y réfléchissant, il y a une "race condition".
Le signal USR1 peut arriver avant que le père soit en pause.
Auquel cas, je suis foutu.

Disons que dans 99,999999% des cas, le fils passera plusieurs
secondes dans boulot1 et donc je suis sauvé.

Mais je voudrais être perfectionniste. J'ai pensé à diverses
méthodes pour résoudre ce problème (par exemple en utilisant
le filesystem) mais toutes choque mon sens de l'esthétique.

Des idées ?

A+

5 réponses

Avatar
Nicolas George
Petit Grasshopper wrote in message
:
Ça marche. Mais en y réfléchissant, il y a une "race condition".
Le signal USR1 peut arriver avant que le père soit en pause.
Auquel cas, je suis foutu.


Classique, avec les signaux spécialement. Heureusement, les versions
modernes d'Unix proposent des solutions. Ici, la solution s'appelle
sigsuspend : c'est pause, mais avec un changement atomique du masque de
signaux. Il suffit donc de masquer USR1 avant de lancer le fils, et de le
démasquer dans le sigsuspend.

Avatar
lhabert
Petit Grasshopper :

Le signal USR1 peut arriver avant que le père soit en pause.
Auquel cas, je suis foutu.


Tu peux faire un sigprocmask avant le fork pour bloquer le signal le temps
que le père se mette en pause.

Enfin personellement j'aurais plutôt relié le père au fils par un pipe, le
fils écrit un caractère dans le pipe, et le père, en guise de pause lit (en
mode bloquant) un caractère sur le pipe.

Avatar
Harpo
Petit Grasshopper wrote:

Bonjour,

J'ai besoin de réaliser un programme qui fait ceci:
- initialisation
- fork()
- le père s'endort
- le fils fait un certain boulot, prévient le père puis s'endort
- le père fait sa part de boulot et meurt
- le fils continue à dormir jusqu'à ce qu'on le réveille


IPC ?

--
http://patrick.davalan.free.fr/

Avatar
Pascal Bourguignon
Petit Grasshopper writes:

Bonjour,

J'ai besoin de réaliser un programme qui fait ceci:
- initialisation
- fork()
- le père s'endort
- le fils fait un certain boulot, prévient le père puis s'endort
- le père fait sa part de boulot et meurt
- le fils continue à dormir jusqu'à ce qu'on le réveille

J'ai fait ça comme ça (en simplifiant) :

newpid = fork();
if (newpid == 0) {
/* fils */
boulot1();
kill(getppid(), SIGUSR1);
pause();
}
else {
/* père */
pause();
boulot2();
exit(0);
}

Ça marche. Mais en y réfléchissant, il y a une "race condition".
Le signal USR1 peut arriver avant que le père soit en pause.
Auquel cas, je suis foutu.

Disons que dans 99,999999% des cas, le fils passera plusieurs
secondes dans boulot1 et donc je suis sauvé.

Mais je voudrais être perfectionniste. J'ai pensé à diverses
méthodes pour résoudre ce problème (par exemple en utilisant
le filesystem) mais toutes choque mon sens de l'esthétique.


Comme dit Harpo, IPC. Dans ce cas, un simple pipe devrait faire
l'affaire:


int f2p[2];
check_result(pipe(f2p));
childpid=fork();
switch(childpid){
case -1:
perror("fork");
exit(1);
break;
case 0:
/* fils */
close(f2p[0]);
boulot1();
{ char buffer=1;int res;while(0==(res=write(f2p[1],&buffer,1)));
if(res<0){perror("write");exit(1);} }
close(f2p[1]);
pause();
exit(0);
break;
default:
/* père */
close(f2p[1]);
{char buffer;int res;while(0==(res=read(f2p[0],&buffer,1)));
if(res<0){perror("write");exit(1);}}
close(f2p[0]);
pause();
boulot2();
exit(0);
break;
}


--
__Pascal Bourguignon__ http://www.informatimago.com/

"By filing this bug report you have challenged the honor of my
family. Prepare to die!"

Avatar
Petit Grasshopper
Nicolas George wrote:

Classique, avec les signaux spécialement. Heureusement, les versions
modernes d'Unix proposent des solutions. Ici, la solution s'appelle
sigsuspend : c'est pause, mais avec un changement atomique du masque de
signaux. Il suffit donc de masquer USR1 avant de lancer le fils, et de le
démasquer dans le sigsuspend.


Oups ! La honte ! Je connaissais sigsuspend, même que j'ai déjà
utilisé par le passé. Mais la programmation Unix ça doit pas être
comme le vélo : on arrête quelques années et on oublie.

Un grand merci quand même.

A+