我想做一个程序,该程序首先创建3个进程(A),然后再创建一个进程(B),并且这些第一个进程必须在管道中写入,该管道在每次该进程写入时最后一个进程读取。 我尝试了一些方法,但我不知道该怎么做,因为流程(B)是在流程(A)之后创建的
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHILDREN 3
int main(int argc, char *argv[])
{
pid_t pid;
int fd[2];
char buffer[100];
char str[] = "Hello";
char str2[] = "Hello2";
char str3[] = "Hello3";
for(int num_process = 0; num_process < MAX_CHILDREN; num_process++)
{
if(pipe(fd) == -1)
{
perror( "pipe Failed" );
continue;
}
pid = fork();
if(pid < 0)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{ //child code
if(num_process == 0){
printf("Child %i (pid= %i) send string %s\n", num_process, getpid(),str);
write(fd[1],str,strlen(str));
}
if(num_process == 1){
printf("Child %i (pid= %i) send string %s\n", num_process, getpid(),str2);
write(fd[1],str2,strlen(str2));
}
if(num_process == 2){
printf("Child %i (pid= %i) send string %s\n", num_process, getpid(),str3);
write(fd[1],str3,strlen(str3));
}
exit(0);
}
else{//parent
printf("Im parent %i\n",getpid());
wait(NULL);
}
}
//Creating another child process from parent, this process recieves string sent from
//childs
pid = fork();
if(pid < 0)
{
perror("fork failed");
exit(1);
}
if(pid == 0){//child
printf("The new process %i read fd pipe\n",getpid());
if( read(fd[0],buffer,sizeof(buffer)) <= 0) //read pipe
{
perror("error read");
exit( EXIT_FAILURE );
}
printf("String readed : %s\n",buffer);
}
else{//parent
wait(NULL);
}
return 0;
}
答案 0 :(得分:2)
您需要对代码进行一些更改。父母不应该真正等孩子们,直到他们全部上马。由于您为前三个子项中的每个子项都创建了一个新管道,因此需要跟踪正在使用的文件描述符。您应该为此使用数组以及要发送的字符串。 read()
和write()
系统都不调用以null结尾的字符串,并且您不要求它在末尾写一个空字节,因此您需要告诉printf()
打印正确的信息。
这些变化和其他变化导致:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_CHILDREN 3
int main(void)
{
pid_t pid;
int fd[MAX_CHILDREN][2];
char buffer[100];
const char *str[MAX_CHILDREN] = { "Hello 1", "Hello 2", "Hello 3" };
for (int i = 0; i < MAX_CHILDREN; i++)
{
if (pipe(fd[i]) == -1)
{
perror("pipe Failed");
exit(1);
}
pid = fork();
if (pid < 0)
{
perror("fork failed");
exit(1);
}
if (pid == 0)
{
printf("Child %i (pid= %i) send string %s\n", i + 1, getpid(), str[i]);
write(fd[i][1], str[i], strlen(str[i]));
exit(i + 1);
}
}
pid = fork();
if (pid < 0)
{
perror("fork failed");
exit(1);
}
if (pid == 0)
{
printf("The new process %i read fd pipe\n", getpid());
for (int i = MAX_CHILDREN; i-- > 0; )
{
int nbytes;
if ((nbytes = read(fd[i][0], buffer, sizeof(buffer))) <= 0)
{
perror("error read");
exit(EXIT_FAILURE);
}
printf("String read: %.*s\n", nbytes, buffer);
}
exit(4);
}
int corpse;
int status;
while ((corpse = wait(&status)) >= 0)
printf("child %d exited with status 0x%.4X\n", corpse, status);
return 0;
}
运行时,输出可能是:
Child 1 (pid= 91027) send string Hello 1
Child 2 (pid= 91028) send string Hello 2
Child 3 (pid= 91029) send string Hello 3
The new process 91030 read fd pipe
String read: Hello 3
String read: Hello 2
String read: Hello 1
child 91027 exited with status 0x0100
child 91028 exited with status 0x0200
child 91029 exited with status 0x0300
child 91030 exited with status 0x0400
我颠倒了阅读循环中元素的顺序,主要是为了好玩。如果愿意,可以改用传统的for (int i = 0; i < MAX_CHILDREN; i++)
循环。
尽管在该程序中并不重要,但是您没有在子级或父级中关闭足够的文件描述符。父级应关闭管道的写端;它不会使用它们。孩子们应该关闭管道的读取端。他们不会使用它们。此外,第二个和第三个孩子应该关闭为第一个打开的管道,第三个孩子应该关闭第二个打开的管道,因为他们也不会使用它们。如果不这样做,第四个子循环等待EOF(返回0字节),它将挂起。
经验法则:如果您
dup2()
管道的一端到标准输入或标准输出,同时关闭两个
由返回的原始文件描述符
pipe()
尽快地。
特别是,在使用任何
exec*()
系列功能。
如果您将描述符与任何一个重复,则该规则也适用
dup()
要么
fcntl()
与F_DUPFD
请注意,该程序的另一种设计将在循环外部创建单个管道,并且子代将全部写入同一管道。您可能想要在消息字符串中添加换行符,以便将结果分开。您肯定要考虑在第四个子对象中循环读取,并且您需要担心管道已正确关闭,依此类推。对它进行编码将是一个值得的子练习。