【问题标题】:Exit statements won't exit all processes退出语句不会退出所有进程
【发布时间】:2024-01-13 23:00:01
【问题描述】:

我目前正在运行一个带有 C++ 程序的 mini shell,当用户键入“exit”时,main_func() 返回-1。此时,将打印 print 语句(在子进程中),然后是 exit,但循环(在父进程中)继续运行。只有当我使用kill shell 命令时它才会真正结束,但这并不能彻底结束我的程序。

终止我的程序的函数

kill(0, SIGINT);  // send an INT signal
kill(0, SIGKILL);

以下是无法正确退出并卡在 mini shell 上的代码。那么我到底做错了什么?是创建流程的方式吗?

pid_t pid_new;
int status2;


int main_func()
{
    // Assume the problematic case: return -1.
    return -1;
}


int main()
{
    while(1){
        if ((pid_new = fork()) == 0){
            if(main_func() == -1){
                cout << "Ending the MiniShell...\n";
                exit(0);    // <--- The exit command
            } else {
                main_func();
            }
        }
        else if ((pid_new < 0)){
            // Error handling
        }
        else
            waitpid(pid_new, &status2,0);
    }
    return 0;
}

【问题讨论】:

  • 您关心的是哪个exit?你到底希望这个exit 做什么?
  • 退出主程序@JaMiT
  • 您关心的是哪个exit?您的代码中有两个 sn-p。 (一个在main_func()返回-1时由子进程的主程序运行,一个在fork()返回负值时由父进程的主程序运行,你问的是哪一个?)
  • 我担心 main_func() 返回 -1 :) @JaMiT。我的实际代码在 main_func() 中要复杂得多,但我认为我无法发布所有代码。它只是一个迷你外壳,应该继续运行直到用户点击“退出”
  • 好的,请不要发布您的整个代码。所有相关的是该函数可以返回-1。代码应该是 minimal reproducible example,而不是 mini-shell。

标签: c++ shell process fork


【解决方案1】:

从根本上说,fork() 创建了一个单独的进程(子进程)。子进程中采取的大部分动作都没有反映在父进程中。 exit() 就是这样一种行为。调用exit() 后,子进程被终止,父进程不受影响(好吧,SIGCHLD 被传递给大部分被忽略的父进程)。

所以要通知父级exit()事件(main_func()返回-1),你需要采用一些额外的机制。一种方法是向父母发出信号。但是要向父级发送信号,则需要父级 PID。与父级不同,fork() 不会在子级中返回父 PID。您需要调用getppid() 来获取父PID。以下代码也是如此:

#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>

pid_t pid_new;
int status2;


int main_func()
{
    // Assume the problematic case: return -1.
    return -1;
}


int main()
{
    while(1){
        if ((pid_new = fork()) == 0){
            if(main_func() == -1){
                cout << "Ending the MiniShell...\n";
                kill(getppid(), SIGINT);   // Interrupt the parent
                exit(0);    // <--- The exit command
            } else {
                main_func();
            }
        }
        else if ((pid_new < 0)){
            // Error handling
        }
        else
            waitpid(pid_new, &status2,0);
    }
    return 0;
}

终端会话:

$ gcc SO.c 
$ ./a.out 
Ending the MiniShell...

$

关于要传递的信号:默认处置为终止的任何信号。由于您没有显示完整代码,我假设没有为SIGINT 安装信号处理程序。或者,如果您希望进行一些清理而不是立即终止,您可以为此注册一个信号处理程序。

【讨论】: