如何在Linux下通过C/C++基于/proc/stat计算单CPU核心利用率
用C/C++计算Linux单CPU核心利用率
嗨,完全不用客气,这个需求其实非常实用,而且原理也很清晰——你说的没错,瞬时CPU状态确实只有忙碌或空闲,但我们要的是一段时间内的平均利用率,这才是实际场景里有参考价值的指标,而/proc/stat就是实现这个的核心依据。
核心原理
/proc/stat文件里,每一行对应一个CPU核心(第一行cpu是所有核心的总和,后面的cpu0、cpu1就是单个核心的数据),每个字段记录的是从系统启动以来,该核心在不同状态下累计消耗的jiffies时间片(通常1个jiffies是1/100秒,不过我们不需要关心具体数值,因为最终算的是比例)。
计算单核心利用率的逻辑很简单:
- 第一次读取目标核心的所有状态累计值,算出总累计时间
total1和空闲累计时间idle1 - 等待一段固定时间(比如1秒,也可以更短)
- 第二次读取同一核心的状态累计值,算出
total2和idle2 - 计算这段时间内的总耗时差
delta_total = total2 - total1,空闲耗时差delta_idle = idle2 - idle1 - 利用率 =
(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
相关产品推荐
相关产品推荐

