Fork (): не возвращать ребенка, пока он не прекратится - PullRequest
1 голос
/ 09 декабря 2010

У меня проблемы с fork () и тому подобными вещами.

Я разрабатываю оболочку, в которой пользователь может писать команды, которые будут выполняться как в обычной и обычной оболочке.

У меня есть такая основная функция:

void Shell::init() {
    string command;
    while (1) {
        cout << getPrompt() << " ";
        command = readCommand();
        if (command.length() > 0) handleCommand(command);
    }
}

handleCommand() - это функция, которая делает практически все. Где-то в этом у меня есть следующее:

...
else {
    pid_t pid;
    pid = fork();

    char* arg[tokens.size() + 1];
    for (int i = 0; i < tokens.size(); ++i) {
        arg[i] = (char*) tokens[i].c_str();
    }
    arg[tokens.size()] = NULL;

    if (pid == 0) {
        if (execvp(tokens[0].c_str(), arg) == -1) {
            cout << "Command not known. " << endl;
        };
    } else {
        wait();
    }
}

Что я хочу, так это то, что когда я достигну этой точки, команда будет считаться вызовом программы, поэтому я создаю дочерний элемент для ее запуска. Он работает почти идеально, но я снова получаю подсказку перед выходом программы. Пример:

tronfi@orion:~/NetBeansProjects/Shell2$ whoami
tronfi@orion:~/NetBeansProjects/Shell2$ tronfi

tronfi@orion:~/NetBeansProjects/Shell2$ 

Ребенок должен умереть после execvp, поэтому он не должен вызывать подсказку, и родитель ждет, пока ребенок не умрет.

Так ... что я делаю не так?

Спасибо !!

Ответы [ 3 ]

3 голосов
/ 10 декабря 2010

Вы звоните wait() неправильно. Ожидается, что ему будет передан указатель на int, в котором будет сохранено состояние выхода дочернего элемента:

int status;
wait(&status);

Правда, вы должны использовать waitpid(), чтобы проверить, какой именно ребенок вам нужен. Вам также необходимо выполнить цикл, если waitpid() прерван сигналом:

int r;
do {
    r = waitpid(pid, &status, 0);
} while (r < 0 && errno == EINTR);
3 голосов
/ 09 декабря 2010

Я не уверен, что это именно проблема, но вы должны убедиться, что ребенок выходит, даже если execvp() не удастся:

if (pid == 0) {
    if (execvp(tokens[0].c_str(), arg) == -1) {
        cout << "Command not known. " << endl;
    };
    exit(1); // or some other error code to indicate execvp() fails
} else {
    wait();
}

Если вы этого не сделаете, то если excecvp() терпит неудачу, тогда вы получите два экземпляра вашей оболочки, что, вероятно, не то, что вы хотите.

0 голосов
/ 12 декабря 2010

Ребенок должен быть прерван с помощью вызова

exit(0)
(только при успехе), так как это помогает очистить память и очистить буфер. Этот статус, возвращаемый потомком, должен проверяться родителем, и только тогда он должен выдавать подсказку.

Дайте мне знать, если вам нужно больше деталей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...