2017-04-01 12 views
0

Je n'arrive pas à comprendre pourquoi un seul enfant envoie des données au parent (seul le premier enfant) .. Quand je dors (5) après que l'enfant1 envoie des données par le canal à parent alors le 2e enfant envoie le même nombre premier au parent.C Pipe entre un parent et 2 enfants

Quelqu'un peut-il m'aider?

//--------------------------Consts--------------------------------- 
 
#define NUM_OF_CHILDS 2 
 
#define N 20 
 
#define WIN 5 
 

 
struct msg{ 
 
\t pid_t _pid; 
 
\t int _prime; 
 
}; 
 

 
//--------------------------Prototypes----------------------------- 
 
bool is_prime(int num); 
 
void terminate(pid_t child_pid[],int fd[2]); 
 
void do_child(int fd[2]); 
 
void print_pair(const int f_arr[],const int s_arr[]); 
 

 
//--------------------------Main------------------------------------- 
 
int main() 
 
{ 
 
\t int f_arr[N] = {0}, 
 
\t \t s_arr[N] = {0}, 
 
\t \t ind, //running on children fork 
 
\t \t count1 = 0, 
 
\t \t count2 = 0, 
 
\t \t victory1 = 0, 
 
\t \t victory2 = 0, 
 
\t \t min = 0; 
 

 
\t int fd[2]; 
 

 
\t bool read1 = false, 
 
\t \t read2 = false; 
 

 
\t srand((unsigned)time(NULL)); 
 
\t pid_t child_pid [NUM_OF_CHILDS];//children pid status array 
 

 
\t struct msg msg1; 
 

 
\t if (pipe(fd) == -1)//pipe fd 
 
\t { 
 
\t \t perror("cannot open pipe"); 
 
\t \t exit(EXIT_FAILURE); 
 
\t } 
 

 
\t for(ind = 0; ind < NUM_OF_CHILDS; ind++) 
 
\t { 
 
\t \t child_pid[ind] = fork();// duplicate the current process 
 

 
\t \t if (child_pid[ind] < 0)//fork failed 
 
\t \t { 
 
\t \t \t perror("Cannot fork()"); 
 
\t \t \t exit(EXIT_FAILURE); 
 
\t \t } 
 

 
\t \t if(child_pid[ind] == 0)/* child : sends message to parent*/ 
 
\t \t \t do_child(fd); 
 
\t } 
 

 
\t /* parent : receives message from child */ 
 
\t close(fd[1]); // close the write-end of the pipe 
 

 
\t //read data from pipe 
 
\t while(read(fd[0],&msg1,sizeof(struct msg)) > 0) 
 
\t { 
 
\t \t if(child_pid[0] == msg1._pid) 
 
\t \t { 
 
\t \t \t f_arr[count1++] = msg1._prime; 
 
\t \t \t read1 = true; 
 
\t \t } 
 

 
\t \t else 
 
\t \t { 
 
\t \t \t s_arr[count2++] = msg1._prime; 
 
\t \t \t read2 = true; 
 
\t \t } 
 

 
\t \t if(read1 && read2) 
 
\t \t { 
 
\t \t \t if(f_arr[min] > s_arr[min]) 
 
\t \t \t \t victory1++; 
 
\t \t \t else if(f_arr[min] < s_arr[min]) 
 
\t \t \t \t victory2++; 
 

 
\t \t \t read1 = false; 
 
\t \t \t read2 = false; 
 
\t \t \t min++; 
 
\t \t } 
 

 
\t \t if(victory1 == WIN || victory2 == WIN) 
 
\t \t \t terminate(child_pid,fd); 
 
\t } 
 

 
\t close(fd[0]);// close the read-end of the pipe 
 
\t print_pair(f_arr,s_arr); 
 

 
\t return EXIT_SUCCESS ; 
 
} 
 
//--------------------------------------------------------------------- 
 
//checking if number is a prime number or not 
 
//and return true or false 
 
bool is_prime(int num) 
 
{ 
 
\t int i; 
 
\t if(num==0 || num==1 || num==2) 
 
\t \t return false; 
 
\t for(i=2;i<=num/2;i++) 
 
\t { 
 
\t \t //the number is not prime 
 
\t \t if(num%i == 0) 
 
\t \t \t return false; 
 
\t } 
 
\t //the number is prime 
 
\t return true; 
 
} 
 
//---------------------------------------------------------------- 
 
void do_child(int fd[2]) 
 
{ 
 
\t struct msg message; 
 
\t int num; 
 

 
\t close(fd[0]); 
 

 
\t while (1) 
 
\t { 
 
\t \t num = rand() % 1000; 
 
\t \t if(is_prime(num)) 
 
\t \t { 
 
\t \t \t message._prime = num; 
 
\t \t \t message._pid = getpid(); 
 
\t \t \t write(fd[1], &message, sizeof(struct msg)); 
 
\t \t } 
 
\t } 
 
} 
 
//---------------------------------------------------------------- 
 
void terminate(pid_t child_pid[],int fd[2]) 
 
{ 
 
\t int ind, 
 
\t loop; 
 

 
\t for(ind = 0; ind < NUM_OF_CHILDS; ind++) 
 
\t { 
 
\t \t close(fd[1]); 
 
\t \t //first to give the process an opportunity to die gratefully before 
 
\t \t //using SIGKILL 
 
\t \t kill(child_pid[ind], SIGTERM); 
 
\t \t bool died = false; 
 
\t \t //It will give the process 5 seconds to die gracefully 
 
\t \t for (loop = 0; loop < 5 && !died; ++loop) 
 
\t \t { 
 
\t \t \t int pid; 
 
\t \t \t //the time the child process takes to close down gracefully. 
 
\t \t \t sleep(1); 
 
\t \t \t //to get the return status of that process and prevent zombie processes. 
 
\t \t \t if (waitpid(child_pid[ind], &pid, WNOHANG) == child_pid[ind]) 
 
\t \t \t \t died = true; 
 
\t \t } 
 
\t \t //if SIGTERM did not killed the child do SIGKILL 
 
\t \t if (!died) 
 
\t \t { 
 
\t \t \t int pid; 
 
\t \t \t kill(child_pid[ind], SIGKILL); 
 
\t \t \t waitpid(child_pid[ind], &pid, 0);// harvest the zombie 
 
\t \t } 
 

 
\t } 
 
} 
 
//------------------------------------------------------------------ 
 
void print_pair(const int f_arr[],const int s_arr[]) 
 
{ 
 
\t int ind; 
 
\t for(ind = 0; ind < N; ind++) 
 
\t { 
 
\t \t if(f_arr[ind] == 0 && s_arr[ind] == 0) 
 
\t \t \t break; 
 
\t \t printf("(%d,%d)\n",f_arr[ind],s_arr[ind]); 
 
\t } 
 
}

Répondre

0

D'abord, les deux processus enfants génèrent la même séquence pseudo-aléatoire, car ils commencent avec la même graine. Pour avoir une chance de numéros différents, vous devez les semer après la fourche, et probablement utiliser quelque chose qui change plus d'une fois par seconde (la chance de les deux ayant des valeurs différentes de time() est très faible même si vous avez déplacé le srand(time(NULL)) après la fourchette). Deuxièmement, vous recevez tous les nombres du premier processus parce qu'il a un début d'avance. Il y a suffisamment de temps pour écrire sur le tuyau pendant que le second processus est en cours de création. Le parent ne commence à lire qu'après la création des deux enfants, de sorte que le premier enfant remplit le tampon de tuyau puis bloque. Les tampons de tuyau sont d'au moins quelques kilo-octets.

Même lorsque j'ai ralenti le processus fils en lui faisant imprimer les nombres sur stderr, le premier générait encore des centaines de nombres avant que le second ne se déclenche.

Alors, que se passe-t-il dans votre boucle principale quand des centaines de messages arrivent de l'enfant 1 et aucun de l'enfant 2? Votre tableau f_arr déborde parce qu'il ne peut contenir que 20. Ensuite, tout peut arriver.

La façon la plus simple d'éviter ce serait de vérifier si count1 == N avant d'essayer de stocker un nombre dans f_arr[count1++], et si oui, juste continue; au message suivant. Vous devriez faire la même chose pour les messages du deuxième enfant, même si cela n'arrivera probablement pas. De cette façon, vous accepterez au plus N les messages de chaque enfant et ignorerez le reste. Vous devrez ajouter une autre condition de fin à la boucle principale: si les deux enfants ont envoyé des messages N, vous devez arrêter. Une autre façon d'aller serait d'utiliser un tuyau séparé pour chaque enfant et une lecture alternative des deux tuyaux pour les garder synchronisés, mais j'ai le sentiment que vous évitiez délibérément cela.

+0

"mais j'ai le sentiment que vous avez délibérément évité cela" - vous avez raison. Tnx pour votre commentaire! –

+0

Je ne peux pas le faire fonctionner :( –