【问题标题】:C Pipe between a parent and 2 childrenC 父母和 2 个孩子之间的管道
【发布时间】:2017-08-26 12:50:58
【问题描述】:

我不明白为什么只有 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]);
	}
}

【问题讨论】:

    标签: c operating-system pipe fork posix


    【解决方案1】:

    首先,两个子进程生成相同的伪随机序列,因为它们从相同的种子开始。要获得不同数字的任何机会,您需要在分叉后播种它们,并且可能使用每秒更改一次以上的东西(即使您移动了它们两个具有不同 time() 值的机会也非常小分叉后的srand(time(NULL)))。

    其次,您将收到来自第一个进程的所有数字,因为它具有领先优势。在创建第二个进程时,有足够的时间写入管道。父级直到两个子级都创建后才开始读取,因此第一个子级填充管道缓冲区然后阻塞。管道缓冲区至少有几千字节。

    即使我通过将数字打印到 stderr 来减慢子进程的速度,第一个进程仍然会在第二个进程开始之前生成数百个数字。

    那么当有数百条消息来自子 1 且没有来自子 2 的消息时,在主循环中会发生什么?您的 f_arr 数组溢出,因为它只有 20 个空间。在那之后,任何事情都可能发生。

    防止这种情况发生的最简单方法是在尝试将数字存储到f_arr[count1++] 之前检查是否count1 == N,如果是,则只需continue; 到下一条消息。即使不太可能发生,您也应该对来自第二个孩子的消息执行相同的操作。

    这样,您最多只能接受来自每个孩子的N 消息,而忽略其余消息。您需要在主循环中添加另一个结束条件:如果两个孩子都发送了N 消息,您需要停止。

    另一种方法是为每个孩子使用单独的管道,并从两个管道交替读取以保持它们同步,但我感觉你故意避免这样做。

    【讨论】:

    • "但我有一种感觉,你是故意回避那个"- 你是对的。 Tnx 为您的评论!
    猜你喜欢
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    相关资源
    最近更新 更多