简体   繁体   English

子进程中的Execl()和父进程中的wait()

[英]Execl() in a child process and wait() in the parent process

I don't understand why the parent process continues executing even if his child process didn't terminate. 我不明白为什么父进程即使子进程没有终止也继续执行。

This is ac: 这是ac:

if (!fork()){
    execl("/bin/sh", "sh", "-c", "gnome-terminal -x ./b", (char *) 0);
}
else {

    int status;
    wait(&status);
    if ((status & 255) == 0) printf("\nProcess regularly exited ");
    printf("adios");
    return 0;
}

and this is bc: 这是不列颠哥伦比亚省:

printf("hello\n");
fflush(0);
getchar();
exit(0);

It happens that the parent process prints "process regularly exited" and "adios" when the child process hasn't terminated and it is waiting for input by getchar() ,and I don't understand why. 当子进程尚未终止并且正在等待getchar()输入时,父进程会打印“定期退出的进程”和“ adios”,而我不明白为什么。

Finally ,how can I force the parent process to wait until the execution of bc is completed? 最后,如何强制父进程等待直到bc的执行完成?

Converting comments into an answer. 将评论转换为答案。

One key question when facing a C program that doesn't work as you expect when executing another is 'what happens in the shell'. 面对无法按预期运行的C程序时,另一个关键问题是“ shell中发生了什么”。 For this question, that translates to: When you run sh -c "gnome-terminal …" from the command line, how long does it take before you get the prompt back? 对于这个问题,它转换为:当您从命令行运行sh -c "gnome-terminal …" ,要多长时间才能返回提示?

It is instantly. 瞬间。

So — surprise, surprise — the same thing happens when you run it from your C code. 因此,令人惊讶的是,当您从C代码运行它时,也会发生同样的事情。 The shell of the sh -c … exits promptly, so your parent process spots its death and exits. sh -c …的外壳会立即退出,因此您的父进程会发现它的死亡并退出。 I think your second program is run as a grandchild or great-grandchild of the process you fork off. 我认为您的第二个程序是作为您分叉过程的孙代或曾孙代运行的。 You have sh , which runs gnome-terminal , which probably forks and the parent exits while the child goes on to manage the terminal and fork a shell that runs your second command (or maybe doesn't use a shell and simply executes your second command). 您有sh ,它运行gnome-terminal ,可能会分叉,而父级会退出,而孩子继续管理终端并分叉运行第二条命令的shell(或者可能不使用shell并只是执行第二条命令)。 A process can only wait for its direct children to die; 一个进程只能等待其直接子进程死亡。 it can't wait for its children's children or more distant descendants. 它不能等它的孩子的孩子或更远的后代。

Now if I add while(1){} at the end of ac before return 0 , and at the end of bc before exit(0) , the top command indicates that I have 4 processes: 2 of ac and 2 of bc . 现在,如果我在return 0之前的ac末尾和exit(0)之前的bc末尾添加while(1){} ,则top命令指示我有4个进程: ac 2个和bc 2个。 Isn't it strange? 奇怪吗?

There are multiple things that could be going on. 可能会发生多种情况。 It could be leftover processes from previous runs. 它可能是先前运行的剩余流程。 You'd need to look at the process trees to know if those processes are related and how they're related. 您需要查看流程树以了解那些流程是否相关以及它们之间的关系。

Thank you they were simply leftover processes. 谢谢,他们只是剩下的过程。

Finally, how can I force the parent process to wait until the execution of bc is completed? 最后,如何强制父进程等待直到bc的执行完成?

Succinctly, you can't make A wait for B to finish. 简而言之,您不能让A等待B完成。 You'd need a way for A to know which process is the B that it should wait for. 您需要让A知道应该等待哪个进程B的方法。 It can't wait directly for it because B is not its own child, so you'd probably end up doing some polling operation to see if B is still around. 它不能直接等待它,因为B不是它自己的孩子,因此您可能最终会进行一些轮询操作以查看B是否仍在附近。 That might be testing with kill() and signal 0; 那可能是用kill()和信号0进行测试; on Linux, you might be able to play with iNotify on the /proc file system (and avoid polling). 在Linux上,您也许可以在/proc文件系统上使用iNotify(并避免轮询)。

You could use signals. 您可以使用信号。 This is a simple, not elegant solution. 这是一个简单但不完善的解决方案。

ac 交流电

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>

void death_handler();

int main(){

sigset_t set;
sigfillset(&set);
sigprocmask(SIG_BLOCK,&set,NULL);
sigemptyset(&set);
sigaddset(&set, SIGUSR1); 
sigprocmask(SIG_UNBLOCK, &set, NULL); //unlock SIGUSR1
signal(SIGUSR1, death_handler);

printf("my pid is %d\n", getpid());

char pid[50];
snprintf(pid, 50, "gnome-terminal -x ./b %d",(int)getpid()); 

if (fork() == 0){

    execl("/bin/sh","sh", "-c", pid,(char *) 0);
}
else {

    int status;
    //nobody, apart from the other process (and anyone that sends me a SIGUSR1 signal) can tell me to exit. It has to send a SIGUSR1 signal.

    pause();

    //UNBLOCK ALL PREVIOUSLY BLOCKED SIGNALS 
    sigemptyset(&set);
    sigfillset(&set);
    sigprocmask(SIG_UNBLOCK, &set, NULL);
    //remove ex-child handler
    signal(SIGUSR1, SIG_DFL);

    printf("adios\n");
    return 0;
}   

}

void death_handler(){

printf("ex-child dead\n");    
}

and this is bc 这是公元前

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int main(int argc, char** argv){

int xmax;
xmax = atoi(argv[1]);
printf("parent pid = %s \n", argv[1]);
fflush(0);
getchar();
kill((pid_t)xmax, SIGUSR1);
printf("sendinga signal to the ex-parent to abort pause()...\n");
exit(0);

}

this basically pauses the parent until someone sends the 10 signal. 这基本上会暂停父级,直到有人发送10信号为止。 It can only be unpaused by someone who send it the SIGUSR1 signal. 发送SIGUSR1信号的人只能将其取消暂停。

Another solution, would probably be to use semaphores. 另一个解决方案可能是使用信号量。 You initialize the semaphore to 0. The parent performs a wait, and then, when the child process is finished you just do a post (in the child), that frees the parent. 您将信号量初始化为0。父级执行等待,然后,子进程完成后,您只需在子级中执行一个发布,即可释放父级。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM