1

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はずなので、プロンプトを呼び出すべきではなく、親は子が死ぬまで待っています。

それで...私は何を間違っていますか?

ありがとう!!

4

3 に答える 3

3

あなたはwait()間違って電話をかけています。子の終了ステータスが格納される int へのポインタが渡されることが期待されます。

int status;
wait(&status);

ただし、実際には、あなたが探しwaitpid()ている特定の子を確認するために使用する必要があります。waitpid()がシグナルによって中断された場合も、ループする必要があります。

int r;
do {
    r = waitpid(pid, &status, 0);
} while (r < 0 && errno == EINTR);
于 2010-12-09T23:04:25.660 に答える
3

これが正確な問題かどうかはわかりませんが、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()失敗した場合に、シェルの2 つのインスタンスが作成されてしまいます。これは、おそらく望んでいるものではありません。

于 2010-12-09T19:34:31.460 に答える
0

子は呼び出しを使用して終了する必要があります

終了(0)
(成功した場合のみ)、これはメモリのクリーニングに役立ち、バッファをフラッシュします。子によって返されたこのステータスは、親によってチェックされる必要があり、それからのみプロンプトが表示されます。

詳細が必要な場合はお知らせください。

于 2010-12-12T13:08:24.317 に答える