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

Ubuntu 20.04下C++获取CPU使用率异常,请求排查问题

CPU使用率读取错误排查与修复

问题现象

在Ubuntu 20.04系统中读取CPU使用率时,始终得到固定错误结果:

Utilization cpu = 0
Utilization core 8 = 100

核心错误分析

1. 数据读取逻辑错误

getPercentageCpu函数存在严重逻辑问题:

  • 在getCPUUsage和Core::getCPUUsage中,已经通过getline读取了目标CPU/core的行数据到str参数中
  • 但getPercentageCpu内部又执行了cpu_stat.ignore(5, ' ')和getline(cpu_stat, str),直接丢弃传入的有效数据,转而读取流中的下一行(甚至可能是不存在的行),导致解析内容完全错误

2. 使用率计算逻辑错误

Linux的/proc/stat文件记录的是系统启动以来的累计CPU时间,并非瞬时使用率。仅读取一次数据计算出的是开机到当前的平均使用率,而非实时使用率,必须读取两次数据(间隔一段时间),通过差值计算才能得到真实的瞬时使用率。

3. 字段解析硬编码问题

代码中固定循环9次解析字段,但/proc/stat的CPU行可能包含更多字段(如guest、guest_nice等),硬编码次数会导致解析不完整或字符串越界访问。

4. Core编号检查缺失

未验证目标core编号是否存在,若传入的编号超出系统实际核心数,会读取到错误的行数据。

修复方案与代码示例

第一步:重构CPU行解析函数

改为动态解析传入的行数据,提取累计时间:

#include <sstream>
#include <string>
#include <utility>

// 解析/proc/stat中的单条CPU记录,返回(idle累计时间, 总累计时间)
std::pair<uint64_t, uint64_t> parseCpuLine(const std::string& line) {
    uint64_t idleTime = 0;
    uint64_t totalTime = 0;
    std::istringstream lineStream(line);
    std::string prefix;

    lineStream >> prefix; // 跳过"cpu"或"cpuX"前缀

    uint64_t timeValue;
    int fieldIndex = 0;
    while (lineStream >> timeValue) {
        totalTime += timeValue;
        // idle是第4个字段(索引从0开始)
        if (fieldIndex == 3) {
            idleTime = timeValue;
        }
        fieldIndex++;
    }

    return {idleTime, totalTime};
}

第二步:修复总CPU使用率读取函数

改为读取两次数据并计算差值:

#include <fstream>
#include <iostream>
#include <unistd.h>
#include <cmath>

uint8_t CPU::getCPUUsage() const {
    std::ifstream statFile("/proc/stat");
    if (!statFile.is_open()) {
        std::cerr << "无法打开/proc/stat\n";
        return -1;
    }

    std::string line;
    std::getline(statFile, line);
    auto [idle1, total1] = parseCpuLine(line);
    statFile.close();

    usleep(100000); // 间隔100ms,可根据需求调整

    statFile.open("/proc/stat");
    std::getline(statFile, line);
    auto [idle2, total2] = parseCpuLine(line);
    statFile.close();

    uint64_t deltaIdle = idle2 - idle1;
    uint64_t deltaTotal = total2 - total1;

    if (deltaTotal == 0) {
        return 0;
    }

    float utilization = (1.0f - static_cast<float>(deltaIdle) / deltaTotal) * 100;
    return static_cast<uint8_t>(std::round(utilization));
}

第三步:修复单Core使用率读取函数

增加Core存在性检查,同样采用两次读取差值计算:

uint8_t Core::getCPUUsage(uint8_t CPUNumber) const {
    std::string targetPrefix = "cpu" + std::to_string(CPUNumber);

    // 第一次读取累计时间
    std::ifstream statFile("/proc/stat");
    if (!statFile.is_open()) {
        std::cerr << "无法打开/proc/stat\n";
        return -1;
    }

    std::string line;
    bool coreFound = false;
    while (std::getline(statFile, line)) {
        if (line.substr(0, targetPrefix.size()) == targetPrefix) {
            coreFound = true;
            break;
        }
    }
    statFile.close();

    if (!coreFound) {
        std::cerr << "核心" << static_cast<int>(CPUNumber) << "不存在\n";
        return -1;
    }

    auto [idle1, total1] = parseCpuLine(line);

    usleep(100000);

    // 第二次读取累计时间
    statFile.open("/proc/stat");
    coreFound = false;
    while (std::getline(statFile, line)) {
        if (line.substr(0, targetPrefix.size()) == targetPrefix) {
            coreFound = true;
            break;
        }
    }
    statFile.close();

    if (!coreFound) {
        std::cerr << "核心" << static_cast<int>(CPUNumber) << "不存在\n";
        return -1;
    }

    auto [idle2, total2] = parseCpuLine(line);

    uint64_t deltaIdle = idle2 - idle1;
    uint64_t deltaTotal = total2 - total1;

    if (deltaTotal == 0) {
        return 0;
    }

    float utilization = (1.0f - static_cast<float>(deltaIdle) / deltaTotal) * 100;
    return static_cast<uint8_t>(std::round(utilization));
}

第四步:调整主函数

由于读取函数内部已经包含间隔等待,可适当调整主循环的sleep时间:

#include "CPU.hpp"

int main() {
    Core info_proc;
    CPU info_cpu;
    uint8_t core_utilization;
    uint8_t cpu_utilization;

    while (1) {
        core_utilization = info_proc.getCPUUsage(8);
        cpu_utilization = info_cpu.getCPUUsage();

        std::cout << "Utilization cpu = " << static_cast<int>(cpu_utilization) << "\n";
        std::cout << "Utilization core 8 = " << static_cast<int>(core_utilization) << "\n";
        std::cout << "\033[H\033[J";
        usleep(500000); // 调整为500ms,避免重复等待
    }
}

内容的提问来源于stack exchange,提问作者Tears4fears

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:18:21