首页 > 解决方案 > 实现允许用户在后台运行多个进程(最多同时三个)的 C++ 程序

问题描述

我是 Linux 新手。以下是我的代码。做这个任务对我来说有点复杂,所以我希望有人能给我提示。我感谢您的帮助。

*注意:我自己也搞砸了我的代码。所以它很糟糕而且未完成,但如果没有任何方向,我真的无法继续。

我正在尝试实现一个名为 BP 的 C/C++ 程序,它允许用户在后台运行多个进程(同时最多三个)。当三个进程当前正在运行时,进一步的执行请求将被挂起(进程状态变为“停止”)并等待直到另一个进程停止或终止。当进程在后台运行时,用户可以输入命令来显示后台进程的信息,停止或杀死一个后台进程。

If users' input = bg [name of executable file] [a list of arguments] Action: BP 在后台运行带有参数列表的可执行文件并继续接受来自用户的输入。如果已经有 3 个正在运行的进程,则停止该进程。

bgkill --> 通过用户输入杀死 pid

我的问题是我不知道如何检查进程的状态以确保后台进程不能超过三个。 流程图在这里。

/.....skipped.../ //问题从bg和bgKill开始

void bg(string input) {
    // Using waitpid() to check child already finished before
    int notRunning = waitpid(bpid, NULL, WNOHANG);
    if (notRunning) status = 0;

    // Check status
    if (status > 3) {
        cout << "Stopped. " << endl;
        return;
    }

    // Check name is null or not
    if (input == "" || input.length() == 0) {
        cout << "BP: > Error: Name is null. " << endl;
        return;
    }

    // Fork a child process
    bpid = fork();
    if (bpid < 0) exit(EXIT_FAILURE);
    else if (bpid > 0) {
        // Parent Code
        cout << "BP: > Background process started with pid " << bpid << endl;
        status += 1;
    } else if (bpid == 0) {
        // Child Code

        // Parse command into array
        // Init Array
        int size = countArg(input);
        char *arg[size + 1];

        // Put substring into array
        string delimiter = " ";
        for (int argCount = 0; argCount < size; argCount++) {
            int pos = input.find(delimiter);
            arg[argCount] = strdup(input.substr(0, pos).c_str());
            input.erase(0, pos + delimiter.length());
        }
        arg[size] = NULL;

        // Execute the command
        if (execvp(arg[0], arg) == -1) {
            // If execute failed
            if (fileExist(arg[0])) {
                cout << "execvp() is failed. Do you mean ./" << arg[0] << "?" << endl;
            } else cout << "execvp() is failed." << endl;
        }
    }
}

void bgKill(string pidStr) {
    // Check status
    if (status == 0) {
        cout << "BP: > No background process to kill." << endl;
        return;
    }

    // Check the pid is the background pid
    int pid = atoi(pidStr.c_str());
    if (pid == 0 || pid != bpid) return invalidProcess(pid);

    // Kill the process
    kill(pid, SIGTERM);
    cout << "BP: > Background process with pid " << pid << " was killed." << endl;

    // Reset all flag
    status = 0;
    bpid = 0;
}

标签: c++linuxprocessmultiprocessing

解决方案


有三个选项:

  • 阻止waitpid。这不是直接的选项,因为您需要同时响应输入,但您可以执行以下操作之一:

    • 阻塞子进程并使用管道或 eventfd 将更改传回,
    • 在单独的线程中阻塞并使用管道、eventfd 或共享内存将更改传回

    然后,您还应该调整主输入循环以使用select,以便您可以响应 STDIN 或子进程/线程上的更改。

  • waitpid像现在一样进行投票。这类似于以前的方法:将主输入循环重写为selectSTDIN 几百毫秒,然后轮询waitpid是否有变化。
  • 最后,您可以为SIGCHLD. 每当子进程停止或终止时,都会调用此函数,因此您可以响应它(例如,通过启动其中一个挂起的进程或设置一个标志)并返回阻塞输入。

推荐阅读