popen
でプロセスへのパイプを開いた後、開始されたプロセスを強制終了する方法はありますか? (pclose
を使用すると、プロセスが終了するのを待つため、私は望んでいませんが、それを強制終了する必要があります。)
popen()
を使用せず、必要なことを実行する独自のラッパーを作成します。
fork()
に移動し、dup2()
を使用してstdin
&stdout
を置き換え、次にexec()
を呼び出すのはかなり簡単です。子。
そうすれば、親は正確な子PIDを持ち、その上でkill()
を使用できます。
popen()
が実行していることを実装する方法に関するサンプルコードについては、Googleで「popen2()の実装」を検索してください。たった十数行の長さです。 dzone.com から取得:次のような例を見ることができます:
#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;
}
注意:popen2()が必要なようですが、私のディストリビューションにはこのメソッドが付属していないようです。
これはpopen2の改良版です(クレジットはSergey Lによるものです)。 slacyによって投稿されたバージョンは、popen2で作成されたプロセスのPIDを返しませんが、sh
に割り当てられたPIDを返します。
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};
popenは実際にはスレッドを開始しませんが、プロセスをフォークします。定義を見ると、そのプロセスのPIDを取得して強制終了する簡単な方法があるようには見えません。プロセスツリーを調べるなどの難しい方法もあるかもしれませんが、パイプ、フォーク、およびexec関数を使用してpopenの動作を模倣する方がよいと思います。次に、fork()から取得したPIDを使用して、子プロセスを強制終了できます。
実際、プロセスがI/Oを実行している場合(そうでない場合は、なぜpopen
(3)の代わりにsystem
?)、次にpclose
は、次に読み取りまたは書き込みを試みたときにSIGPIPE
でそれを叩き、フォールオーバーする必要がありますうまく:-)
関数popen2を作成する@slacyのアイデアに従いました。
しかし、子プロセスが終了すると問題が見つかりました。ファイル記述子outfp
をまだ読み取っている親プロセスが関数から戻りません。
これは、親プロセスに未使用のクローズパイプを追加することで修正できます。
close(p_stdin[READ]);
close(p_stdout[WRITE]);
シェルとしてbashを使用することで、新しいプロセスの正しいpidを取得できます。
execl("/bin/bash", "bash", "-c", command, NULL);
子プロセスが死ぬと、関数の呼び出し元popen2
呼び出しによって子プロセスのステータスを収集する必要がありますpclose2
。そのステータスを収集しない場合、子プロセスは終了時にゾンビプロセスになる可能性があります。
これは、テストされ、期待どおりに機能する完全なコードです。
#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)
{
dup2(p_stdin[READ], STDIN_FILENO);
dup2(p_stdout[WRITE], STDOUT_FILENO);
//close unuse descriptors on child process.
close(p_stdin[READ]);
close(p_stdin[WRITE]);
close(p_stdout[READ]);
close(p_stdout[WRITE]);
//can change to any exec* function family.
execl("/bin/bash", "bash", "-c", command, NULL);
perror("execl");
exit(1);
}
// close unused descriptors on parent process.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
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;
}
int
pclose2(pid_t pid) {
int internal_stat;
waitpid(pid, &internal_stat, 0);
return WEXITSTATUS(internal_stat);
}
最初の行に(bash)スクリプトを入力するだけです。
echo PID $$
次に、pidを読み取り、それを使用して:kill(pid、9)を実行します。
私はPythonで同様のことをしました。そこでは、サブプロセスとそのためにフォークされたサブプロセスを強制終了できます。それは実際にはslacyのソリューションに似ています。 http://www.pixelbeat.org/libs/subProcess.py
明らかな方法はsystem( "pkill process_name");です。
プロセスの複数のインスタンスが実行されている場合、これは明らかに問題があります。