【发布时间】:2017-08-02 08:20:16
【问题描述】:
我在处理管道和子进程时遇到了一些问题。
我需要
- 使用 fork() 创建四个孩子
- 使用 pipe() 在父级和每个子级之间建立双向通信
- 从包含多个字符串的文件 card.txt 中读取数据
- 以循环方式将字符串分配给每个孩子 A B C D E F G H,孩子 1 得到 A E,孩子 2 得到 B F,依此类推
- 选择一个成员变量 -> 使用 write() 和 read() 以及 close() 将变量发送到父级以关闭未使用的管道端
- 打印父进程中收到的变量
预期的输出是:
$ ./a.out 1C < card.txt
Child : 1, pid 1593 :
<S2 S3 S9 ><H9 H6 HA H8 ><C6 CK ><D8 DQ D7 D3 >
Child : 2, pid 1594 :
<SA S6 S7 S4 ><H4 HJ H7 ><CQ C9 CT ><DT D2 D9 >
Child : 3, pid 1595 :
<SQ S5 ><H2 ><C7 C5 C8 CA C4 CJ C3 ><DA D5 >
Child : 4, pid 1596 :
<S8 SJ SK ST ><HK HT H5 H3 HQ ><C2 ><D4 D6 >
child 1: H9
parent: child 1 played H9
child 2: CQ
parent: child 2 played CQ
child 3: H2
parent: child 3 played H2
child 4: HK
parent: child 4 played HK
但是,实际输出如下:
parent: child 1 played (null)parent: child 2 played (null)parent: child 3 played (null)parent: child 4 played (null)
这是为什么呢?如何解决问题?
代码创建了这个输出:
#include <stdio.h>
#include <string.h>
#define BUFFERSIZE 51
int i=0;
int currpid, s;
char *buf[BUFFERSIZE];
char *array[BUFFERSIZE];
int n;
char *buffer[100];
/** child to parent pipe */
int child_parent[2];
/** parent to child pipe */
int parent_child[2];
/** child2 to parent pipe */
int child2_parent[2];
/** parent to child2 pipe */
int parent_child2[2];
/** child3 to parent pipe */
int child3_parent[2];
/** parent to child3 pipe */
int parent_child3[2];
/** child4 to parent pipe */
int child4_parent[2];
/** parent to child4 pipe */
int parent_child4[2];
void childFunction(){
int j;
for( i = s+1; i < BUFFERSIZE; i += 4 )
{
buf[j] = array[i];
j++;
}
printf("\n<");
int r;
char *e;
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'S');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">");
printf("<");
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'H');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">");
printf("<");
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'C');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">");
printf("<");
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'D');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">\n");
switch (s){
case 0:
close(parent_child[1]);
close(parent_child[0]);
close(child_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child_parent[1], &buffer[0], strlen(buffer[0]));
close(child_parent[1]);
break;
case 1:
close(parent_child2[1]);
close(parent_child2[0]);
close(child2_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child2_parent[1], &buffer[0], strlen(buffer[0]));
close(child2_parent[1]);
break;
case 2:
close(parent_child3[1]);
close(parent_child3[0]);
close(child3_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child3_parent[1], &buffer[0], strlen(buffer[0]));
close(child3_parent[1]);
break;
case 3:
close(parent_child4[1]);
close(parent_child4[0]);
close(child4_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child4_parent[1], &buffer[0], strlen(buffer[0]));
close(child4_parent[1]);
break;
}
}
void parentFunction(){
switch (s){
case 0:
close(child_parent[1]);
close(parent_child[1]);
close(parent_child[0]);
read(child_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child_parent[0]);
break;
case 1:
close(child2_parent[1]);
close(parent_child2[1]);
close(parent_child2[0]);
read(child2_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child2_parent[0]);
break;
case 2:
close(child3_parent[1]);
close(parent_child3[1]);
close(parent_child3[0]);
read(child3_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child3_parent[0]);
break;
case 3:
close(child4_parent[1]);
close(parent_child4[1]);
close(parent_child4[0]);
read(child4_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child4_parent[0]);
break;
}
}
int main(int argc, char *argv[])
{
int ch;
ssize_t rread;
char *line = NULL;
size_t len = 0;
while (rread = getdelim( &line, &len, '\0', stdin) != -1) {
}
array[i] = strtok(line," ");
while(array[i]!=NULL)
{
array[++i] = strtok(NULL," ");
}
int childlimit = 4;
int childpids[childlimit];
int currpid;
if (pipe(child_parent) == 0 && pipe(parent_child) == 0 && pipe(child2_parent) == 0 && pipe(parent_child2) == 0 && pipe(child3_parent) == 0 && pipe(parent_child3) == 0 && pipe(child4_parent) == 0 && pipe(parent_child4) == 0)
{
for(s=0; s<childlimit; s++){
switch(currpid = fork()){
case 0:
printf("Child : %d, pid %d : ", s+1, getpid() );
childFunction();
break;
case -1:
printf("Error when forking\n");
return 1;
default:
// in the father
childpids[s] = currpid;
parentFunction();
break;
}
}
//wait for all child created to die
waitpid(-1, NULL, 0);
}
}
【问题讨论】:
-
你听说过这些叫做“函数”的东西吗?它们有助于使代码更清晰。主函数中子处理的代码太多了。将流程管理保留在
main();将字符串处理和 I/O 操作委托给仅在子进程中运行的函数。您并没有真正在孩子中关闭足够的文件描述符。如果父项需要写入其子项,则您在父项中关闭了太多文件描述符;如果父母不需要写信给孩子,你为什么要为从父母到孩子的管道烦恼? -
@JonathanLeffler,更新后的代码将父子代码移动到不同的函数中,在我的实现中,它需要父子写入,但此时由于问题尚未开发。
-
在函数中使用全局变量
i进行循环控制是一场灾难。有时,全局变量是必要的——当它们需要时,你应该使用它们。大多数情况下,它们不是——当它们不是时,你不应该使用它们。单字母全局变量名称很少适用。 (最好在每个需要它的函数中重复i的定义,而不是像你所做的那样。)这使得你的代码很难分析。您的字符串读取循环仅保留最后一个“行”(以空值结尾的“行”)。我想这是在一次操作中吞食整个文件的一种方式。 -
您的代码不会将字符串的选择写入子项——您根本没有使用父子管道。这违背了您为程序提供的规范。因为你有 8 个管道,16 个描述符,你的子进程应该分别关闭 14 个描述符——它们只需要保持从父进程到子进程的管道读取端和从子进程到子进程的写入端保持打开状态。父母。您拨打
waitpid()等待任何一个孩子死去;你需要一个循环来等待他们全部死去。 -
如果您提供了输入数据,您应该从中获得预期的输出数据,这也会有很大帮助。它是如何布置的并不明显。