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每秒钟会被唤醒多次(子线程被SIGSEGV信号停止)。这似乎与Java正在为自己的目的使用SIGSEGV有关(请参见此问题和此文章)。
所有这些唤醒最终导致应用程序变得非常缓慢。因此,我想知道我的解决方案是否存在一些缺陷,并且是否有办法使其与Java应用程序一起正常工作。
waitpid()
只等待子进程而不是孙子进程,因此我认为你走错了路。 - alkwaitpid
手册页中,它指出以下Linux特定选项用于使用clone(2)创建的子进程...
(指的是__WALL
等)。因此,某种程度上似乎应该可以等待线程。无论如何,我会继续寻找解决方案,同时希望有人已经在这方面做过,并发布了解决方案 :) - betabandido/proc/PID/task/TID/
扫描方法呢?它只适用于Linux系统,而且你无法获得通知,但是扫描/proc/PID/task/
非常轻量级。你需要一个例子吗? - Nominal Animal