Реализовать программу C ++, которая позволяет пользователю запускать несколько процессов (до трех одновременно) в фоновом режиме - PullRequest
0 голосов
/ 25 февраля 2020

Я новичок в Linux. Ниже приведены мои коды. Мне немного сложно выполнить эту задачу, поэтому у меня есть sh, который может дать мне подсказку. Я ценю вашу помощь.

* Внимание: я тоже запутался в своем коде. Так что это плохо и незакончено, но я действительно не могу продолжать без какого-либо направления.

Я пытаюсь реализовать программу на C / C ++ под названием BP, которая позволяет пользователю запускать несколько процессов (до трех одновременно) в фоновом режиме. Когда в данный момент запущены три процесса, дальнейший запрос на выполнение будет отложен (состояние процесса изменено на «остановлено») и ожидает, пока другой процесс не будет остановлен или завершен. Пока процессы выполняются в фоновом режиме, пользователь может ввести команду для отображения информации о фоновых процессах, остановить или завершить фоновый процесс.

Если пользовательский ввод = bg [имя исполняемого файла] [список arguments] Действие: BP запускает исполняемый файл со списком аргументов в фоновом режиме и продолжает принимать ввод от пользователя. Если уже есть 3 запущенных процесса, процесс останавливается .;

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

1 Ответ

1 голос
/ 25 февраля 2020

Существует три варианта:

  • Блокировка на waitpid. Это не напрямую вариант, так как вам нужно ответить на входные данные, но вы можете сделать одно из следующего:

    • блок в дочернем процессе и сообщить об изменениях обратно, используя трубу или eventfd,
    • блок в отдельном потоке и сообщайте об изменениях обратно, используя трубу, eventfd или разделяемую память

    Затем вы должны также настроить свой основной вход l oop использовать select, чтобы вы могли реагировать на изменения либо в STDIN, либо в дочернем процессе / потоке.

  • Опрос waitpid, как и сейчас. Это похоже на предыдущий подход: переписать ваш основной ввод l oop в select на STDIN в течение нескольких сотен миллисекунд, а затем опросить с помощью waitpid, если что-то изменилось.
  • Наконец, вы можете зарегистрироваться обработчик сигнала для SIGCHLD. Эта функция будет вызываться всякий раз, когда дочерний процесс останавливается или завершается, поэтому вы можете ответить на него (например, запустив один из ожидающих процессов или установить флаг) и вернуться к блокировке ввода.
...