wait 命令不会等待子进程完成 c cpp c++
我正在尝试编写一个 C++ 程序,该程序创建一个子进程,运行一个命令并将输出传输回父进程正在运行的命令的输入。
我让父进程执行 wait(NULL) 或 wait((void*)pid) 命令,但它不等待。
这是代码:
#include <string.h>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, char * argv[])
{
char* commands[strlen(argv[1])];
char *command = NULL;
command = strtok(argv[1],"|");
int i = 0;
while(command != NULL)
{
commands[i] = command;
i++;
command = strtok(NULL,"|");
}
int numberOfCommands = i;
pid_t pid;
int pfd[2];
char* prgname = NULL;
if(pipe(pfd) == -1)
{
perror("error on pipe call");
return(1);
}
for(int j = 0;j<numberOfCommands;j++)
{
cout<<commands[j]<<endl;
}
pid = fork();
if(pid == 0){//child process
printf("Child: My PID = %d\n", getpid());
printf("Child: Running...\n");
close(pfd[0]); //close read end of pipe
dup2(pfd[1],1);//connect the pipes
close(pfd[1]);//close extra file descriptors
prgname = commands[0];//first command
cout<<"child starting command: "<<prgname<<endl;
execlp(prgname, prgname, 0);//Load the program
**printf("Child: Done sleeping, returning.\n");**
}
else
{
printf("Parent: My PID = %d\n", getpid());
**wait((void*)pid); //also tried wait(NULL); same effect
printf("Parent: Running...\n");**
close(pfd[1]); //close the write end of the pipe
dup2(pfd[0],0);//connect the pipes
close(pfd[0]); //close extra file descriptor
prgname = commands[1];//now run the second command
cout<<"parent starting command: "<<prgname<<endl;
execlp(prgname, prgname, 0);//Load the programm
}
cout<<"all done"<<endl;
return 0;
}
不要采用粗体线。我希望父进程在 wait() 命令处等待,子进程会打印出“Child did sleep...”,然后完成,然后父进程会打印出“Parent: running...”
我在做什么错误的!
谢谢!
更新:程序的完整输出为:
dmegs
more
Child: My PID = 30070
Child: Running...
Parent: My PID = 30066
Parent: Running...
parent starting command: more
child starting command: dmegs
Child: Done sleeping, returning.
all done
I am trying to write a c++ program that creates a child process, runs a command and pipes the output back to the input of a command the parent is running.
I have the parent execute the wait(NULL) or wait((void*)pid) command but it does not wait.
here is the code:
#include <string.h>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, char * argv[])
{
char* commands[strlen(argv[1])];
char *command = NULL;
command = strtok(argv[1],"|");
int i = 0;
while(command != NULL)
{
commands[i] = command;
i++;
command = strtok(NULL,"|");
}
int numberOfCommands = i;
pid_t pid;
int pfd[2];
char* prgname = NULL;
if(pipe(pfd) == -1)
{
perror("error on pipe call");
return(1);
}
for(int j = 0;j<numberOfCommands;j++)
{
cout<<commands[j]<<endl;
}
pid = fork();
if(pid == 0){//child process
printf("Child: My PID = %d\n", getpid());
printf("Child: Running...\n");
close(pfd[0]); //close read end of pipe
dup2(pfd[1],1);//connect the pipes
close(pfd[1]);//close extra file descriptors
prgname = commands[0];//first command
cout<<"child starting command: "<<prgname<<endl;
execlp(prgname, prgname, 0);//Load the program
**printf("Child: Done sleeping, returning.\n");**
}
else
{
printf("Parent: My PID = %d\n", getpid());
**wait((void*)pid); //also tried wait(NULL); same effect
printf("Parent: Running...\n");**
close(pfd[1]); //close the write end of the pipe
dup2(pfd[0],0);//connect the pipes
close(pfd[0]); //close extra file descriptor
prgname = commands[1];//now run the second command
cout<<"parent starting command: "<<prgname<<endl;
execlp(prgname, prgname, 0);//Load the programm
}
cout<<"all done"<<endl;
return 0;
}
Take not of the bolded lines. I would expect the parent process to wait at the wait() command and the child would print out "Child done sleeping..." and then finish and then the parent would print out "Parent: running..."
What am I doing wrong!
Thanks!
Update: full output to program is:
dmegs
more
Child: My PID = 30070
Child: Running...
Parent: My PID = 30066
Parent: Running...
parent starting command: more
child starting command: dmegs
Child: Done sleeping, returning.
all done
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我看到四个问题:
1)
execlp()
失败:execlp()
(或任何exec
系列函数)完全取代了当前正在运行的进程映像如果成功 - 预计不会返回,除非出现问题。但您看到的是“孩子:睡觉完毕,正在返回”消息,因此它不可能成功。 (在您的示例中,我猜测这可能是因为dmegs
应该是dmesg
。)2)
printf()
和cout
输出缓冲意味着无法保证您按照发生的顺序获得输出。如果您想通过打印输出来调试它,最好打印到stderr
(例如使用fprintf(stderr, ...)
),这是(默认情况下)无缓冲。3)正如其他人指出的,
wait((void *)pid)
是错误的。wait(NULL)
或waitpid(pid, NULL, 0)
。4) 这是否是一个问题取决于平台,但是...
execlp()
的终止空指针参数应该显式写为(char *)0
(char *)0 code> 而不仅仅是0
,以确保它作为指针而不是整数传递。一般来说,在 C 中,指针上下文中的0
根据定义是空指针,但是当将参数传递给参数数量可变的函数时,编译器没有足够的信息来知道您正在尝试在指针上下文中使用它,因此除非您显式转换它,否则会将其作为整数传递。在指针和整数大小不同的平台上,这可能会给您带来麻烦。所以我认为 wait() 正在工作,子进程实际上并没有运行您想要的命令,并且父进程和子进程的输出由于缓冲而变得混合。
这是代码的稍微修改版本,它不使用任何 C++,删除了命令处理内容,只是将
sleep 5
的输出通过管道传输到cat
(这是毫无意义的,因为sleep
无论如何都不会生成任何输出,但延迟对于查看发生的情况很有用):输出:
(这里有 5 秒的延迟)
I see four problems:
1)
execlp()
is failing:execlp()
(or any of theexec
family of functions) completely replaces the currently running process image if successful - it is not expected to return, unless something goes wrong. But you are seeing the "Child: Done sleeping, returning" message, so it cannot have succeeded. (In your example, I would guess that this is probably becausedmegs
should have beendmesg
.)2)
printf()
andcout
output buffering means that there is no guarantee whatsoever that you are getting the output in the order in which it happens. If you want to debug this by printing output, you would be better off printing tostderr
(e.g. withfprintf(stderr, ...)
) which is (by default) unbuffered.3) As noted by others,
wait((void *)pid)
is wrong.wait(NULL)
orwaitpid(pid, NULL, 0)
.4) Whether this one is a problem or not is platform-dependent, but... the terminating null pointer argument to
execlp()
should be explicitly written as(char *)0
rather than just0
, to ensure that it is passed as a pointer rather than an integer. In general in C,0
in a pointer context is by definition a null pointer, but when passing parameters to functions with variable numbers of arguments, the compiler does not have enough information to know that you are trying to use it in a pointer context, and so will pass it as an integer unless you explicitly cast it. This can get you into trouble on platforms where pointers and integers are not the same size.So I reckon the
wait()
is working, the child is not actually running the command you want, and the output from parent and child is getting mixed up due to buffering.Here is a slightly modified version of your code, which doesn't use any C++, cuts out the command handling stuff, and just pipes the output of
sleep 5
tocat
(which is rather pointless, assleep
doesn't generate any output anyway, but the delay is useful to see what's going on):Output:
(there is a 5 second delay here)
您通常会打开结果以允许错误情况
等待您想要使用的特定子项
或等待任何子项
You would normally switch on the result to allow for the error case
Waiting for a specific child you would want to use
or waiting for any child
你为什么要
等待需要指向状态的指针
你几乎肯定会传递不可写的地址。测试一下等待重新编码,我敢打赌一定会抱怨得很厉害;
另外,混合 printf 和 couts 也是一种让自己感到困惑的方法,它们的缓冲/刷新方案可能不同
why are you doing
wait takes pointer to status
You are almost certanly passing non writable address. Test the wait retcode and I bet is is complaining big time;
Also mixing printf and couts is a way to confuse yourself, their buffering / flushing schemes can be different
你不应该仅仅为了让编译器停止抱怨而将东西强制转换为 void* 。 :)
看来您可能需要waitpid:http://linux. die.net/man/2/waitpid
更新:
您需要检查 execlp 调用是否确实有效。比较:
与:
第一种情况,由于execlp找不到“dmegs”,所以子进程基本上立即退出。这会解除父进程的阻塞并允许其执行。
You shouldn't cast things to void* just to make the compiler stop complaining. :)
It looks like you probably want waitpid: http://linux.die.net/man/2/waitpid
Update:
You need to check whether the execlp call actually worked. Compare:
with:
In the first case, since execlp can't find "dmegs", the child process basically exits immediately. This unblocks the parent process and allows it to execute.