c-使用waitpid等待另一个进程的线程

我正在尝试使用waitpid()等待单个线程而不是进程.我知道pthread_join()或std :: thread :: join()是等待线程的典型方法.但是,就我而言,我正在开发一个监视应用程序,该应用程序将分叉并执行(通过execv)一个程序,该程序又会生成一些线程.因此,我无法加入来自监视应用程序的线程,因为它们属于不同的进程,并且我无法访问源代码.不过,我希望能够等待这些单独的线程完成.

为了更直观地了解我要实现的目标,我提供了一张图纸,以期使其更加清晰:

使用进程时一切正常,但是waitpid不等待线程.基本上,waitpid在调用后立即返回-1(该线程在那时仍在运行几秒钟).

waitpid状态的文档:

In the Linux kernel, a kernel-scheduled thread is not a distinct construct from a process. Instead, a thread is simply a process that is created using the Linux-unique clone(2) system call; other routines such as the portable pthread_create(3) call are implemented using clone(2). Before Linux 2.4, a thread was just a special case of a process, and as a consequence one thread could not wait on the children of another thread, even when the latter belongs to the same thread group. However, POSIX prescribes such functionality, and since Linux 2.4 a thread can, and by default will, wait on children of other threads in the same thread group.

该描述仅考虑从一个线程等待其他线程的孩子(在我的情况下,我想等待另一个进程的孩子).但是,至少,它表明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每秒会唤醒多次(子线程被SI​​GSEGV信号停止).这似乎与Java将SIGSEGV用于其自身目的有关(请参见this questionthis post).

所有这些唤醒最终会大大降低应用程序的速度.所以我想知道我的解决方案是否存在缺陷,是否有办法使其与Java应用程序一起使用.

解决方法:

我对您所说的一切对于流程“都可以正常工作”的说法感到有些困惑. waitpid只能等待您自己的子进程,而不能等待其他任意进程,实际上,除非是您自己的子进程,否则几乎肯定会使用进程id的错误.

与其寻找丑陋的骇客来做不可能做的事情,不如不修改您的设计以使用某种适当的进程间通信机制,以便线程在完成时可以向其他进程发出信号,而不是进行修复?还是将整个程序放在单个进程(具有多个线程)中,而不是将工作分散在多个进程和线程中?

上一篇:wait,waitpid


下一篇:深入理解计算机系统 第八章 异常控制流(2)