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

如何在Linux下通过C/C++基于/proc/stat计算单CPU核心利用率

用C/C++计算Linux单CPU核心利用率

嗨,完全不用客气,这个需求其实非常实用,而且原理也很清晰——你说的没错,瞬时CPU状态确实只有忙碌或空闲,但我们要的是一段时间内的平均利用率,这才是实际场景里有参考价值的指标,而/proc/stat就是实现这个的核心依据。

核心原理

/proc/stat文件里,每一行对应一个CPU核心(第一行cpu是所有核心的总和,后面的cpu0、cpu1就是单个核心的数据),每个字段记录的是从系统启动以来,该核心在不同状态下累计消耗的jiffies时间片(通常1个jiffies是1/100秒,不过我们不需要关心具体数值,因为最终算的是比例)。

计算单核心利用率的逻辑很简单:

  1. 第一次读取目标核心的所有状态累计值,算出总累计时间total1和空闲累计时间idle1
  2. 等待一段固定时间(比如1秒,也可以更短)
  3. 第二次读取同一核心的状态累计值,算出total2和idle2
  4. 计算这段时间内的总耗时差delta_total = total2 - total1,空闲耗时差delta_idle = idle2 - idle1
  5. 利用率 = (delta_total - delta_idle) / delta_total * 100%

这里要注意:通常我们把idle(纯空闲)和iowait(等待IO时的空闲)都算作空闲时间,因为此时CPU并没有在执行计算任务;如果你的场景需要把iowait算入忙碌时间,只需要调整空闲时间的计算范围即可。

C++实现示例

下面是一个完整的示例代码,用来计算cpu0核心的每秒利用率:

#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <thread>
#include <sstream>
#include <vector>

// 读取指定CPU核心的累计时间数据
bool read_cpu_stats(const std::string& cpu_name, unsigned long long& total, unsigned long long& idle) {
    std::ifstream stat_file("/proc/stat");
    if (!stat_file.is_open()) {
        std::cerr << "Failed to open /proc/stat" << std::endl;
        return false;
    }

    std::string line;
    while (std::getline(stat_file, line)) {
        if (line.substr(0, cpu_name.size()) == cpu_name) {
            std::istringstream iss(line);
            std::string ignore;
            unsigned long long user, nice, system, idle_time, iowait, irq, softirq, steal, guest, guest_nice;
            
            // 解析/proc/stat的字段:cpuX user nice system idle iowait irq softirq steal guest guest_nice
            iss >> ignore >> user >> nice >> system >> idle_time >> iowait >> irq >> softirq >> steal >> guest >> guest_nice;
            
            // 总时间:所有字段之和
            total = user + nice + system + idle_time + iowait + irq + softirq + steal + guest + guest_nice;
            // 空闲时间:idle + iowait(可根据需求调整)
            idle = idle_time + iowait;
            return true;
        }
    }

    std::cerr << "CPU " << cpu_name << " not found" << std::endl;
    return false;
}

int main() {
    const std::string target_cpu = "cpu0"; // 要监控的核心,比如cpu1、cpu2等
    unsigned long long total1, idle1, total2, idle2;

    // 第一次读取
    if (!read_cpu_stats(target_cpu, total1, idle1)) {
        return 1;
    }

    // 等待1秒(可以用更精确的计时,比如std::chrono)
    std::this_thread::sleep_for(std::chrono::seconds(1));

    // 第二次读取
    if (!read_cpu_stats(target_cpu, total2, idle2)) {
        return 1;
    }

    // 计算利用率
    unsigned long long delta_total = total2 - total1;
    unsigned long long delta_idle = idle2 - idle1;
    double utilization = 0.0;
    if (delta_total > 0) {
        utilization = (delta_total - delta_idle) * 100.0 / delta_total;
    }

    std::cout << target_cpu << " utilization: " << utilization << "%" << std::endl;

    return 0;
}

关键细节说明

  • 为什么用累计值的差值? 因为/proc/stat里的数值是从开机到现在的总时间,只有两次读取的差值才是我们监控的那段时间内的实际消耗,这样计算出来的平均利用率才是有意义的。
  • 关于时间间隔 示例里用了1秒,如果你需要更频繁的采样(比如每100毫秒),可以把std::chrono::seconds(1)改成std::chrono::milliseconds(100),不过间隔太短可能会导致数值波动较大。
  • 错误处理 代码里加入了文件打开失败、核心不存在的判断,实际使用时可以根据需求扩展更多异常处理逻辑。
  • 和getloadavg的区别 你提到的getloadavg返回的是系统负载(等待CPU的进程数+正在运行的进程数),它反映的是系统的繁忙程度,而不是CPU实际的利用率,所以确实不符合你的需求。

内容的提问来源于stack exchange,提问作者NK-cell

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:24:07