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

Execl() in a child process and wait() in the parent process

我不明白为什么即使他的子进程没有终止,父进程也会继续执行。

这是a.c:

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;
}

这是b.c:

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

碰巧子进程还没有终止,等待getchar()的输入,父进程打印了"process regularly exited"和"adios",我不明白为什么。

最后,如何强制父进程等待b.c执行完成?

正在将评论转化为答案。

当 C 程序在执行另一个程序时无法按预期工作时,一个关键问题是 'what happens in the shell'。对于这个问题,这转化为: 当您从命令行 运行 sh -c "gnome-terminal …" 时,需要多长时间才能收到提示?

It is instantly.

所以 — 惊喜,惊喜 — 当您从 C 代码 运行 时,同样的事情发生了。 sh -c … 的 shell 立即退出,因此您的 parent 进程发现它的死亡并退出。我认为您的第二个程序是 运行 作为您分叉的过程的宏伟 child 或 great-grandchild。你有 sh,其中 运行s gnome-terminal,它可能会分叉并且 parent 退出,而 child 继续管理终端并分叉 shell 那 运行 是你的第二个命令(或者可能不使用 shell 而只是执行你的第二个命令)。一个进程只能等待它的直接children死掉;它等不及它的 children 的 children 或更远的后代了。

Now if I add while(1){} at the end of a.c before return 0, and at the end of b.c before exit(0), the top command indicates that I have 4 processes: 2 of a.c and 2 of b.c. Isn't it strange?

可能会发生多种情况。它可能是之前 运行 的剩余进程。您需要查看进程树以了解这些进程是否相关以及它们如何相关。

Thank you they were simply leftover processes.

Finally, how can I force the parent process to wait until the execution of b.c is completed?

简而言之,您不能让 A 等待 B 完成。您需要一种方法让 A 知道哪个进程是它应该等待的 B。它不能直接等待它,因为 B 不是它自己的 child,因此您可能最终会执行一些轮询操作以查看 B 是否仍在附近。这可能是用 kill() 和信号 0 进行测试;在 Linux 上,您可以在 /proc 文件系统上使用 iNotify(并避免轮询)。

您可以使用信号。这是一个简单而不优雅的解决方案。

a.c

#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");    
}

这是b.c

#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);

}

这基本上会暂停父进程,直到有人发送 10 信号。它只能由发送 SIGUSR1 信号的人取消暂停。

另一个解决方案可能是使用信号量。您将信号量初始化为 0。父进程执行等待,然后,当子进程完成时,您只需执行 post(在子进程中),释放父进程。