我不明白为什么只有 1 个子节点向父节点发送数据(只有第一个子节点)。 当我在 child1 通过管道向父级发送数据后执行 sleep(5) 时,第二个子级向父级发送相同的素数。
有人可以帮助我吗?
//--------------------------Consts---------------------------------
#define NUM_OF_CHILDS 2
#define N 20
#define WIN 5
struct msg{
pid_t _pid;
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()
{
int f_arr[N] = {0},
s_arr[N] = {0},
ind, //running on children fork
count1 = 0,
count2 = 0,
victory1 = 0,
victory2 = 0,
min = 0;
int fd[2];
bool read1 = false,
read2 = false;
srand((unsigned)time(NULL));
pid_t child_pid [NUM_OF_CHILDS];//children pid status array
struct msg msg1;
if (pipe(fd) == -1)//pipe fd
{
perror("cannot open pipe");
exit(EXIT_FAILURE);
}
for(ind = 0; ind < NUM_OF_CHILDS; ind++)
{
child_pid[ind] = fork();// duplicate the current process
if (child_pid[ind] < 0)//fork failed
{
perror("Cannot fork()");
exit(EXIT_FAILURE);
}
if(child_pid[ind] == 0)/* child : sends message to parent*/
do_child(fd);
}
/* parent : receives message from child */
close(fd[1]); // close the write-end of the pipe
//read data from pipe
while(read(fd[0],&msg1,sizeof(struct msg)) > 0)
{
if(child_pid[0] == msg1._pid)
{
f_arr[count1++] = msg1._prime;
read1 = true;
}
else
{
s_arr[count2++] = msg1._prime;
read2 = true;
}
if(read1 && read2)
{
if(f_arr[min] > s_arr[min])
victory1++;
else if(f_arr[min] < s_arr[min])
victory2++;
read1 = false;
read2 = false;
min++;
}
if(victory1 == WIN || victory2 == WIN)
terminate(child_pid,fd);
}
close(fd[0]);// close the read-end of the pipe
print_pair(f_arr,s_arr);
return EXIT_SUCCESS ;
}
//---------------------------------------------------------------------
//checking if number is a prime number or not
//and return true or false
bool is_prime(int num)
{
int i;
if(num==0 || num==1 || num==2)
return false;
for(i=2;i<=num/2;i++)
{
//the number is not prime
if(num%i == 0)
return false;
}
//the number is prime
return true;
}
//----------------------------------------------------------------
void do_child(int fd[2])
{
struct msg message;
int num;
close(fd[0]);
while (1)
{
num = rand() % 1000;
if(is_prime(num))
{
message._prime = num;
message._pid = getpid();
write(fd[1], &message, sizeof(struct msg));
}
}
}
//----------------------------------------------------------------
void terminate(pid_t child_pid[],int fd[2])
{
int ind,
loop;
for(ind = 0; ind < NUM_OF_CHILDS; ind++)
{
close(fd[1]);
//first to give the process an opportunity to die gratefully before
//using SIGKILL
kill(child_pid[ind], SIGTERM);
bool died = false;
//It will give the process 5 seconds to die gracefully
for (loop = 0; loop < 5 && !died; ++loop)
{
int pid;
//the time the child process takes to close down gracefully.
sleep(1);
//to get the return status of that process and prevent zombie processes.
if (waitpid(child_pid[ind], &pid, WNOHANG) == child_pid[ind])
died = true;
}
//if SIGTERM did not killed the child do SIGKILL
if (!died)
{
int pid;
kill(child_pid[ind], SIGKILL);
waitpid(child_pid[ind], &pid, 0);// harvest the zombie
}
}
}
//------------------------------------------------------------------
void print_pair(const int f_arr[],const int s_arr[])
{
int ind;
for(ind = 0; ind < N; ind++)
{
if(f_arr[ind] == 0 && s_arr[ind] == 0)
break;
printf("(%d,%d)\n",f_arr[ind],s_arr[ind]);
}
}
最佳答案
首先,两个子进程生成相同的伪随机序列,因为它们以相同的种子开始。为了获得不同数字的机会,您需要在 fork 后为它们播种,并且可能使用每秒更改一次以上的东西(它们两个具有不同 time() 值的机会
即使您在 fork 之后移动了 srand(time(NULL)) ,它也非常小。
其次,您会收到来自第一个进程的所有数字,因为它具有领先优势。创建第二个进程时有足够的时间写入管道。父级直到创建两个子级后才开始读取,因此第一个子级填充了管道缓冲区,然后阻塞。管道缓冲区至少有几千字节。
即使我通过将数字打印到 stderr 来减慢子进程的速度,第一个进程仍然会在第二个进程开始之前生成数百个数字。
那么,当有数百条消息来自子进程 1 而没有来自子进程 2 的消息时,主循环中会发生什么情况?您的 f_arr
数组溢出,因为它只有 20 个空间。之后,任何事情都可能发生。
防止这种情况的最简单方法是在尝试将数字存储到 f_arr[count1++]
之前检查是否 count1 == N
,如果是,则 继续;
到下一条消息。您应该对来自第二个 child 的消息执行相同的操作,即使这种情况不太可能发生。
这样,您将最多接受来自每个 child 的 N
条消息,并忽略其余的消息。您需要向主循环添加另一个结束条件:如果两个子循环都发送了 N
条消息,则需要停止。
另一种方法是为每个子级使用单独的管道,并从两个管道交替读取以保持它们同步,但我有一种感觉,您故意避免这样做。
关于C 父级和 2 个子级之间的管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43154402/