You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C/C++中跨进程获取目标活跃线程的资源使用信息?

Great question! Let's break this down clearly—first how to implement thread monitoring in C/C++, then how to pull resource usage data (like total CPU time and input operations) from threads in other processes without touching their source code or the OS kernel. I'll cover both Linux and Windows since those are the most common environments.

Thread Monitoring in C/C++

We can split this into two scenarios: monitoring threads within your own process, and monitoring threads in external processes (which is what you're most interested in for the second part of your question).

In-Process Thread Monitoring

For threads you create yourself, the native APIs give you direct access to their metadata and resource usage:

  • Linux: Use pthread APIs like pthread_getattr_np() to fetch thread attributes, and pthread_self() to get the current thread ID. To track CPU time, you can call clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) to get the thread-specific CPU time.
  • Windows: After creating a thread with CreateThread(), you hold a handle to it. Use GetThreadTimes() to get user/kernel mode CPU time, and GetThreadPriority() to check its priority level.

Cross-Process Thread Monitoring (No Source/Kernel Modifications)

This is the core of your question, and both platforms have standard, non-intrusive ways to do this:

Linux Platform

Linux's /proc filesystem is your best friend here—it's a virtual filesystem that exposes real-time process/thread data without requiring kernel changes or target program modifications.

  • Thread Enumeration: List all threads of a target process by looking at the subdirectories under /proc/[PID]/task/—each subdirectory name is a thread ID (TID).
  • Total CPU Time: For each thread, read the /proc/[PID]/task/[TID]/stat file. The 14th field (utime) is user-mode CPU time, and the 15th field (stime) is kernel-mode CPU time, both measured in jiffies. Convert these to seconds by dividing by sysconf(_SC_CLK_TCK).
  • Input/IO Operations: Read the /proc/[PID]/task/[TID]/io file—fields like rchar (total bytes read by the thread) and read_bytes (actual disk reads) give you input operation metrics.
  • Simpler Alternative: Use the libprocps library (part of most Linux distros) to wrap /proc parsing, so you don't have to manually parse text files. Functions like readproc() can fetch thread data directly.

Here's a quick C example to fetch a thread's CPU time:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int get_thread_cpu_time(pid_t pid, pid_t tid, double *user_sec, double *sys_sec) {
    char path[256];
    snprintf(path, sizeof(path), "/proc/%d/task/%d/stat", pid, tid);
    FILE *fp = fopen(path, "r");
    if (!fp) return -1;

    char buf[1024];
    if (!fgets(buf, sizeof(buf), fp)) {
        fclose(fp);
        return -1;
    }

    // Parse utime (14th field) and stime (15th field)
    long utime, stime;
    int fields_read = sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %ld %ld", &utime, &stime);
    fclose(fp);
    if (fields_read != 2) return -1;

    long clk_tck = sysconf(_SC_CLK_TCK);
    *user_sec = (double)utime / clk_tck;
    *sys_sec = (double)stime / clk_tck;
    return 0;
}

int main() {
    pid_t target_pid = 1234; // Replace with your target process ID
    pid_t target_tid = 1235; // Replace with your target thread ID
    double user, sys;
    if (get_thread_cpu_time(target_pid, target_tid, &user, &sys) == 0) {
        printf("Thread %d (PID %d) CPU Time: User %.2fs | Kernel %.2fs\n", target_tid, target_pid, user, sys);
    } else {
        perror("Failed to retrieve thread CPU time");
    }
    return 0;
}

Windows Platform

Windows provides native APIs to enumerate threads and fetch their resource data without modifying the target or kernel:

  • Thread Enumeration: Use CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0) to take a snapshot of all system threads, then Thread32First()/Thread32Next() to filter threads belonging to your target PID.
  • Total CPU Time: For each thread ID, call OpenThread(THREAD_QUERY_INFORMATION, FALSE, tid) to get a thread handle, then use GetThreadTimes() to retrieve user-mode and kernel-mode CPU time (converted from FILETIME to seconds by dividing by 10^7).
  • Input/IO Operations: Windows doesn't expose thread-level IO stats directly via simple APIs—you'll need to use Event Tracing for Windows (ETW). ETW lets you capture IO events associated with specific threads without modifying the target program. You'll need to register a trace session, enable IO providers, and parse the events to aggregate thread-level IO data.

Here's a C++ example to enumerate a process's threads and print their CPU time:

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

void print_thread_cpu_times(DWORD target_pid) {
    HANDLE h_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (h_snapshot == INVALID_HANDLE_VALUE) {
        printf("CreateToolhelp32Snapshot failed: %d\n", GetLastError());
        return;
    }

    THREADENTRY32 thread_entry;
    thread_entry.dwSize = sizeof(THREADENTRY32);
    if (!Thread32First(h_snapshot, &thread_entry)) {
        printf("Thread32First failed: %d\n", GetLastError());
        CloseHandle(h_snapshot);
        return;
    }

    do {
        if (thread_entry.th32OwnerProcessID == target_pid) {
            HANDLE h_thread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread_entry.th32ThreadID);
            if (h_thread) {
                FILETIME create_time, exit_time, kernel_time, user_time;
                if (GetThreadTimes(h_thread, &create_time, &exit_time, &kernel_time, &user_time)) {
                    // Convert FILETIME (100-nanosecond intervals) to seconds
                    ULARGE_INTEGER kernel, user;
                    kernel.LowPart = kernel_time.dwLowDateTime;
                    kernel.HighPart = kernel_time.dwHighDateTime;
                    user.LowPart = user_time.dwLowDateTime;
                    user.HighPart = user_time.dwHighDateTime;

                    double kernel_sec = (double)kernel.QuadPart / 10000000.0;
                    double user_sec = (double)user.QuadPart / 10000000.0;

                    printf("Thread ID: %lu | User Time: %.2fs | Kernel Time: %.2fs\n",
                           thread_entry.th32ThreadID, user_sec, kernel_sec);
                } else {
                    printf("GetThreadTimes failed for thread %lu: %d\n", thread_entry.th32ThreadID, GetLastError());
                }
                CloseHandle(h_thread);
            } else {
                printf("OpenThread failed for thread %lu: %d\n", thread_entry.th32ThreadID, GetLastError());
            }
        }
    } while (Thread32Next(h_snapshot, &thread_entry));

    CloseHandle(h_snapshot);
}

int main() {
    DWORD target_pid = 1234; // Replace with your target process ID
    print_thread_cpu_times(target_pid);
    return 0;
}
Key Considerations
  • Permissions: On Linux, you'll need read access to /proc (most users can read their own processes; root is needed for others). On Windows, your program needs PROCESS_QUERY_INFORMATION access to the target process and THREAD_QUERY_INFORMATION for threads.
  • Performance: Reading /proc or using Windows snapshot APIs is lightweight and won't impact target processes significantly. ETW can have minor overhead if tracing high-volume events, but it's still non-intrusive.
  • Compatibility: /proc is standard across all Linux distros. Windows APIs like CreateToolhelp32Snapshot work on XP and later; ETW is supported from Vista onwards.

内容的提问来源于stack exchange,提问作者Jean-Luc Nacif Coelho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:13:30