管道卡在读取中(C - 系统调用)
pipe stuck in read (C - system calls)
这对我来说是第一次使用 C,所以到目前为止一直很困难。
我的程序读取 file.txt。
第一行是我必须创建的 child 的数量(var: NPROC),在剩下的行中我必须读取 child 的进程 ID、两个整数和一个字符那是我必须计算的操作:
例如:
NPROC
(id) (n1) (op) (n2)
2
2 3 + 1
1 5 / 2
2 9 * 3
我必须使用消息队列(完美运行)将操作(逐行)发送到 child,然后 child 应该使用管道发回结果。
这是代码:
(父亲)
//other code
for(i=0; i < NPROC; i++) {
if(pipe(p) == -1) {
perror("pipe");
exit(1);
}
switch(currentPid = fork()){
case 0:
execl("./child", "./child", NULL);
return 0;
case -1:
printf("Error when forking\n");
break;
default:
// in the father
childrenPids[i] = currentPid; // store current child pid
wait(NULL);
printf("\nParentpid: %d, Childpid: %i \n", getpid(), currentPid);
//close(p[1]);
if(read(p[0], &val, sizeof(val) == -1){
perror("read()\n");
exit(1);
}
printf("Parent(%d) received value: %d\n", getpid(), val);
break;
}
//other code
(child)
//other code
while (1) {
long msgtype = m->mtype;
if(msgrcv(msgid, m, sizeof(message) - sizeof(m->mtype), msgtype, IPC_NOWAIT) == -1) {
// if(close (p[1]) == -1){
// perror("close p[1] of the child\n");
// }
//perror("\nmsgrcv");
exit(1);
}
result[i] = calcolate_results(m);
// printf("%i %i %c %i", m->id, m->num1, m->op, m->num2);
printf("\nresult: %i\n", result[i]);
val = result[i];
if(write (p[1], &val, sizeof(val)) == -1) {
perror("write\n");
exit(1);
}
printf("Child(%d) send val: %d\n", getpid(), val);
}
//other code
现在我的问题是父亲的阅读似乎没有收到消息。
当我执行程序不退出时,它在父亲的读取处循环(保持 stuch)。
我试图将读取放在 for 之外(因此它至少应该读取最后一条消息)但程序仍然停留在读取中。
所以如果有人能帮助我,我将不胜感激。
您的代码充满问题。
switch(currentPid = fork()){
case 0:
这里需要关闭管道的读端:
close(p[0]);
通常您会在此处的 execl
之前有一个 dup2
。通常,如果您的 child 进程要加载另一个程序,您希望将其标准输出重定向到管道的写入端,如 dup2(p[1], 1); close(p[1]);
.
execl("./child", "./child", NULL);
return 0;
case -1:
printf("Error when forking\n");
break;
default:
// in the father
childrenPids[i] = currentPid; // store current child pid
wait(NULL);
这个 wait
调用在错误的地方。如果 child 输出的数据多于管道一次可以容纳的数据,那么这里就会出现死锁(child 将阻塞在 write
,等待 parent 到 read
管道退出前的一些数据;parent 将阻塞在 wait
,等待 child 退出,然后再从管道读取。
在你给它做任何事情之前等待 child 退出也是没有意义的。这不应该是一种 coprocess-like 设计,即 children 应该保持 运行 沿着 parent,根据要求进行运算并将结果发回?
printf("\nParentpid: %d, Childpid: %i \n", getpid(), currentPid);
//close(p[1]);
为什么这个 close
被注释掉了? parent 进程关闭管道的写入端至关重要(因为否则从管道的读取端读取将阻塞,因为写入端仍在某处打开(在本例中,在同一进程中))。
if(read(p[0], &val, sizeof(val) == -1){
这一行甚至无法编译。它缺少 )
.
perror("read()\n");
exit(1);
}
您缺少 EOF 检查。 read
到达数据末尾时将 return 0(并保持 val
未初始化)。
您应该使用管道中的所有可用数据(直到 read
returns 0
),然后才 waitpid(currentPid, NULL, 0);
.
这对我来说是第一次使用 C,所以到目前为止一直很困难。 我的程序读取 file.txt。 第一行是我必须创建的 child 的数量(var: NPROC),在剩下的行中我必须读取 child 的进程 ID、两个整数和一个字符那是我必须计算的操作: 例如:
NPROC
(id) (n1) (op) (n2)
2
2 3 + 1
1 5 / 2
2 9 * 3
我必须使用消息队列(完美运行)将操作(逐行)发送到 child,然后 child 应该使用管道发回结果。
这是代码:
(父亲)
//other code
for(i=0; i < NPROC; i++) {
if(pipe(p) == -1) {
perror("pipe");
exit(1);
}
switch(currentPid = fork()){
case 0:
execl("./child", "./child", NULL);
return 0;
case -1:
printf("Error when forking\n");
break;
default:
// in the father
childrenPids[i] = currentPid; // store current child pid
wait(NULL);
printf("\nParentpid: %d, Childpid: %i \n", getpid(), currentPid);
//close(p[1]);
if(read(p[0], &val, sizeof(val) == -1){
perror("read()\n");
exit(1);
}
printf("Parent(%d) received value: %d\n", getpid(), val);
break;
}
//other code
(child)
//other code
while (1) {
long msgtype = m->mtype;
if(msgrcv(msgid, m, sizeof(message) - sizeof(m->mtype), msgtype, IPC_NOWAIT) == -1) {
// if(close (p[1]) == -1){
// perror("close p[1] of the child\n");
// }
//perror("\nmsgrcv");
exit(1);
}
result[i] = calcolate_results(m);
// printf("%i %i %c %i", m->id, m->num1, m->op, m->num2);
printf("\nresult: %i\n", result[i]);
val = result[i];
if(write (p[1], &val, sizeof(val)) == -1) {
perror("write\n");
exit(1);
}
printf("Child(%d) send val: %d\n", getpid(), val);
}
//other code
现在我的问题是父亲的阅读似乎没有收到消息。 当我执行程序不退出时,它在父亲的读取处循环(保持 stuch)。 我试图将读取放在 for 之外(因此它至少应该读取最后一条消息)但程序仍然停留在读取中。 所以如果有人能帮助我,我将不胜感激。
您的代码充满问题。
switch(currentPid = fork()){
case 0:
这里需要关闭管道的读端:
close(p[0]);
通常您会在此处的 execl
之前有一个 dup2
。通常,如果您的 child 进程要加载另一个程序,您希望将其标准输出重定向到管道的写入端,如 dup2(p[1], 1); close(p[1]);
.
execl("./child", "./child", NULL);
return 0;
case -1:
printf("Error when forking\n");
break;
default:
// in the father
childrenPids[i] = currentPid; // store current child pid
wait(NULL);
这个 wait
调用在错误的地方。如果 child 输出的数据多于管道一次可以容纳的数据,那么这里就会出现死锁(child 将阻塞在 write
,等待 parent 到 read
管道退出前的一些数据;parent 将阻塞在 wait
,等待 child 退出,然后再从管道读取。
在你给它做任何事情之前等待 child 退出也是没有意义的。这不应该是一种 coprocess-like 设计,即 children 应该保持 运行 沿着 parent,根据要求进行运算并将结果发回?
printf("\nParentpid: %d, Childpid: %i \n", getpid(), currentPid);
//close(p[1]);
为什么这个 close
被注释掉了? parent 进程关闭管道的写入端至关重要(因为否则从管道的读取端读取将阻塞,因为写入端仍在某处打开(在本例中,在同一进程中))。
if(read(p[0], &val, sizeof(val) == -1){
这一行甚至无法编译。它缺少 )
.
perror("read()\n");
exit(1);
}
您缺少 EOF 检查。 read
到达数据末尾时将 return 0(并保持 val
未初始化)。
您应该使用管道中的所有可用数据(直到 read
returns 0
),然后才 waitpid(currentPid, NULL, 0);
.