waitpid()
プロセスではなく、個々のスレッドを待機するために使用しようとしています。pthread_join()
またはstd::thread::join()
がスレッドを待つ典型的な方法であることを私は知っています。ただし、私の場合はexecv
、プログラムをフォークして (経由で) 実行し、次にいくつかのスレッドを生成する監視アプリケーションを開発しています。そのため、監視アプリケーションからスレッドに参加することはできません。スレッドは別のプロセスに属しており、ソース コードにアクセスできないためです。それでも、これらの個々のスレッドが終了するのを待つことができるようにしたい.
私が達成しようとしていることを簡単に視覚化するために、より明確にすることを望んで、図を含めます。
プロセスを使用するとすべて正常に動作しますがwaitpid
、スレッドを待機しません。基本的に、呼び出された直後にwaitpid
戻ります(スレッドはその時点でさらに数秒間実行されています)。-1
waitpid
州のドキュメント:
Linux カーネルでは、カーネル スケジュール スレッドは、プロセスとは別個の構成体ではありません。代わりに、スレッドは、Linux 固有の clone(2) システム コールを使用して作成される単なるプロセスです。移植可能な pthread_create(3) 呼び出しなどの他のルーチンは、clone(2) を使用して実装されます。Linux 2.4 より前では、スレッドはプロセスの特殊なケースに過ぎず、結果として、別のスレッドが同じスレッド グループに属している場合でも、あるスレッドは別のスレッドの子を待つことができませんでした。しかし、POSIX はそのような機能を規定しており、Linux 2.4 以降では、スレッドは同じスレッド グループ内の他のスレッドの子を待機することができ、デフォルトで待機します。
その説明は、スレッドから他のスレッドの子への待機のみを考慮しています (私の場合、別のプロセスのスレッドの子を待機したい)。しかし、少なくとも、それwaitpid
はスレッド対応であることを示しています。
これは私がスレッドを待つために使用しているものです:
std::vector<pid_t> pids;
/* fill vector with thread IDs (LWP IDs) */
for (pid_t pid : pids) {
int status;
pid_t res = waitpid(pid, &status, __WALL);
std::cout << "waitpid rc: " << res << std::endl;
}
このコードは、プロセスの待機には機能しますが、スレッドの待機には失敗します (__WALL
フラグが使用されていても)。
実際に を使用してスレッドを待つことができるかどうか疑問に思っていますwaitpid
。使用する必要がある他のフラグはありますか? 別のプロセスのスレッドを待つ方法が説明されているドキュメントを教えてください。
参考までに、スレッドの作成に使用しているコードは次のとおりです。
static void foo(int seconds) {
int tid;
{
std::lock_guard<std::mutex> lock(mutex);
tid = syscall(__NR_gettid);
std::cout << "Thread " << tid << " is running\n";
pids.push_back(tid);
pids_ready.notify_all();
}
for (int i = 0; i < seconds; i++)
std::this_thread::sleep_for(std::chrono::seconds(1));
}
static void create_thread(int seconds) {
std::thread t(foo, seconds);
threads.push_back(std::move(t));
}
std::vector<pid_t> create_threads(int num, int seconds) {
for (int i = 0; i < num; i++)
create_thread(seconds);
std::unique_lock<std::mutex> lock(mutex);
pids_ready.wait(lock, [num]() { return pids.size() == num; });
return pids;
}
GCC 4.6 と Ubuntu 12.04 を使用しています。
更新:次を使用して機能させることができましたptrace
:
ptrace(PTRACE_ATTACH, tid, NULL, NULL);
waitpid(tid, &status, __WALL);
ptrace(PTRACE_CONT, tid, NULL, NULL);
while (true) {
waitpid(tid, &status, __WALL);
if (WIFEXITED(status)) // assume it will exit at some point
break;
ptrace(PTRACE_CONT, tid, NULL, NULL);
}
このコードは、T1、T2、...、Tn がプロセスである場合とスレッドである場合の両方で機能します。
ただし、問題があります。この監視ツールをマルチスレッド C++ アプリケーションで試すと、すべて正常に動作します。しかし、当初の目的は、複数のスレッドを生成する Java アプリケーションでこの監視ツールを使用することでした。マルチスレッド Java アプリケーションを使用するwaitpid
と、ループ内で 1 秒間に何度も起動します (子スレッドは SIGSEGV シグナルによって停止されます)。これは、Java が独自の目的で SIGSEGV を使用しているという事実に関連しているようです (この質問とこの投稿を参照してください)。
これらのウェイクアップはすべて、アプリケーションの速度を大幅に低下させます。私のソリューションに何らかの欠陥があるかどうか、またそれを Java アプリケーションで動作させる方法があるかどうか疑問に思っています。