2017-04-01 77 views
0

我不明白爲什麼只有一個孩子發送數據給家長(只有第一個孩子).. 當我做睡眠(5)後,通過管道發送數據到父母然後第二個孩子向父母發送相同的素數。父母和2個孩子之間的管道

有人可以幫助我嗎?因爲他們已經開始使用相同的種子

//--------------------------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 } 
 
}

回答

0

首先,兩個子進程產生相同的僞隨機序列。要獲得不同數字的機會,您需要將它們播種到叉子後面,並且可能使用每秒更改超過一次的東西(即使您移動了srand(time(NULL)),它們的兩個具有不同值time()的機會也非常小之後)。

其次,您正在接收來自第一個過程的所有數字,因爲它具有領先優勢。在第二個過程正在創建時,有足夠的時間寫入管道。直到創建了兩個子項之後,父項纔開始讀取,因此第一個子項將填充管道緩衝區,然後進行阻塞。管道緩衝區至少有幾千字節。

即使當我通過將數字打印到stderr來減慢子進程時,第一個數字仍然會在第二個數字出現之前生成數百個數字。

那麼當從孩子1到達數百條消息而沒有從孩子2到達時,在主循環中會發生什麼?你的f_arr數組溢出,因爲它只有20的空間。之後,任何事情都可能發生。

,以防止將嘗試一些存儲到f_arr[count1++]前檢查是否count1 == N最簡單的方法,如果是這樣,只是continue;下一條消息。您應該對來自第二個孩子的消息也這樣做,即使這不可能發生。

這樣你最多可以接收來自每個孩子的N消息,而忽略其餘的。您需要向主循環添加另一個結束條件:如果兩個孩子都發送了N消息,則需要停止。

另一種方法是爲每個孩子使用一個單獨的管道,並從兩個管道交替讀取以保持其同步,但我有一種感覺,你故意避免這種情況。

+0

「但我有一種感覺,你故意避免這種情況」 - 你是對的。 Tnx爲您的評論! –

+0

我不能得到它的工作:( –