0

関数 popen2 (stackoverflow の他の場所で推奨されている) を使用して、しばらくしてから再度強制終了する必要があるプロセスをプログラムで作成しています。popen2 は PID を返し、この PID を使用してプロセスを強制終了できると考えました。ただし、この方法では機能しません。それを殺すには、返された PID をインクリメントする必要がありますが、これはわかりません (以下のコードを参照)。

さまざまなスレッドがこれを並行して実行している場合、別の問題が発生する可能性があります。その場合、競合状態のために PID が複数異なる可能性があると思います。

私の質問は次のとおりです。マルチスレッド シナリオで popen2 によって作成されたプロセスの PID を確実に特定するにはどうすればよいですか?

#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

#define READ 0
#define WRITE 1

pid_t popen2(const char *command, int *infp, int *outfp) {

    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execl("/bin/sh", "sh", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

main() {
    pid_t pid;

    // Create process
    pid = popen2("crafty", &in, &out);

    sleep(5);

    // Why doesn't kill(pid, SIGKILL) work?
    kill(pid+1, SIGKILL);

    while (1); 
}
4

2 に答える 2

6

私はそれを手に入れたと思います。

execl("/bin/sh", "sh", "-c", command, NULL);

実行し、 pidshを返します。popen2あなたがそれを呼び出すkillと killsしますがsh、子プロセスには触れませんcommand。実際には、次の pid を殺すとまぐれですcommand。これは常に機能するとは限らず、競合状態次第です。

ターゲットプロセスを強制終了できるようにしたい場合は、それを直接開始する必要があります。

警告 (テストされていないコード):

pid_t popen2(const char **command, int *infp, int *outfp) {

    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execvp(*command, command);
        perror("execvp");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

の形式でコマンドを渡します

char *command[] = {"program", "arg1", "arg2", ..., NULL};

あなたの特定の例では:

char *command[] = {"crafty", NULL};
于 2012-10-08T09:51:38.463 に答える
1

保留中のプロセスを回避するには、シェルの「exec」コマンドを使用できます。また、 popen2 は未使用のパイプの書き込み側を閉じます。そうでない場合、パイプは開いたままになります。ポインター (infp、outpf) のいずれかが NULL の場合、パイプを作成してすぐに閉じても意味がありません。私のプロジェクトで使用する popen2 のバージョンは次のとおりです。

pid_t popen2(char *command, int *in_fd, int *out_fd) {
    int     pin[2], pout[2];
    pid_t   pid;
    char    cmd[strlen(command)+10];

    if (out_fd != NULL) {
        if (pipe(pin) != 0) return(-1);
    }
    if (in_fd != NULL) {
        if (pipe(pout) != 0) {
            if (out_fd != NULL) {
                close(pin[0]);
                close(pin[1]);
            }
            return(-1);
        }
    }

    pid = fork();

    if (pid < 0) {
        if (out_fd != NULL) {
            close(pin[0]);
            close(pin[1]);
        }
        if (in_fd != NULL) {
            close(pout[0]);
            close(pout[1]);
        }
        return pid;
    }
    if (pid==0) {
        if (out_fd != NULL) {
            close(pin[1]);
            dup2(pin[0], 0);
        }
        if (in_fd != NULL) {
            close(pout[0]);
            dup2(pout[1], 1);
        }
        // Exec makes possible to kill this process 
        sprintf(cmd, "exec %s", command);
        execlp("sh", "sh", "-c", cmd, NULL);
        fprintf(stderr, "%s:%d: Exec failed in popen2. ", __FILE__, __LINE__);
        perror("Error:");
        exit(1);
    }
    if (in_fd != NULL) {
        close(pout[1]);
        *in_fd = pout[0];
    }
    if (out_fd != NULL) {
        close(pin[0]);
        *out_fd = pin[1];
    }
    return pid;
}
于 2013-12-21T12:00:06.357 に答える