悠悠楠杉
Linux系统下获取CPU占用率的C语言实现指南
一、理解Linux CPU使用率统计原理
在Linux系统中,CPU使用率数据存储在/proc/stat
虚拟文件中,这个动态生成的文件包含了自系统启动以来所有CPU活动的累计时间。理解其统计机制是开发监控工具的关键。
/proc/stat
文件格式示例:
cpu 1024 512 896 123456 78 23 45 0
cpu0 512 256 448 61728 39 11 22 0
cpu1 512 256 448 61728 39 12 23 0
...
各列含义依次为(单位:jiffies,通常1 jiffies=10ms):
1. user:用户态运行时间
2. nice:低优先级用户态时间
3. system:内核态运行时间
4. idle:空闲时间
5. iowait:I/O等待时间
6. irq:硬件中断时间
7. softirq:软件中断时间
8. steal:虚拟化环境偷取时间
计算核心公式:
总时间 = user + nice + system + idle + iowait + irq + softirq + steal
使用率 = (总时间 - idle) / 总时间 * 100%
二、C语言实现方案
1. 基础实现代码
c
include <stdio.h>
include <stdlib.h>
include <string.h>
include <unistd.h>
typedef struct {
unsigned long user;
unsigned long nice;
unsigned long system;
unsigned long idle;
unsigned long iowait;
unsigned long irq;
unsigned long softirq;
unsigned long steal;
} CPUData;
void readcpudata(CPUData *data) {
FILE *file = fopen("/proc/stat", "r");
if (!file) {
perror("Failed to open /proc/stat");
exit(EXITFAILURE);
}
char line[256];
fgets(line, sizeof(line), file); // 读取第一行CPU汇总数据
sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu",
&data->user, &data->nice, &data->system, &data->idle,
&data->iowait, &data->irq, &data->softirq, &data->steal);
fclose(file);
}
double calculateusage(const CPUData *prev, const CPUData *curr) {
unsigned long prevtotal = prev->user + prev->nice + prev->system +
prev->idle + prev->iowait + prev->irq +
prev->softirq + prev->steal;
unsigned long curr_total = curr->user + curr->nice + curr->system +
curr->idle + curr->iowait + curr->irq +
curr->softirq + curr->steal;
unsigned long total_diff = curr_total - prev_total;
unsigned long idle_diff = curr->idle - prev->idle;
return (total_diff - idle_diff) * 100.0 / total_diff;
}
int main() {
CPUData prev, curr;
// 首次读取作为基准
read_cpudata(&prev);
sleep(1); // 等待1秒获取采样间隔
while (1) {
read_cpudata(&curr);
double usage = calculate_usage(&prev, &curr);
printf("CPU Usage: %.2f%%\n", usage);
// 更新为当前值,准备下次计算
prev = curr;
sleep(1);
}
return 0;
}
2. 代码优化方向
- 多核CPU支持:通过解析
cpu0
、cpu1
等行实现各核心独立监控 - 异常处理:增加对
/proc/stat
读取失败的重试机制 - 性能优化:使用缓存减少文件I/O操作
- 时间间隔自适应:动态调整采样频率
三、实际应用中的注意事项
- 首次读数问题:程序首次运行需要建立基准数据,建议丢弃第一次计算结果
- 数值溢出处理:32位系统上jiffies可能溢出,需要增加溢出检测
- 容器环境适配:在Docker等容器中可能需要访问宿主机的
/proc/stat
- 权限要求:确保程序有访问
/proc
文件系统的权限
四、扩展应用场景
- 系统监控工具:集成到自定义的监控系统中
- 性能分析:结合进程监控分析特定应用的CPU消耗
- 资源限制:作为自动扩缩容系统的决策依据
- 嵌入式开发:在资源受限设备上实现轻量级监控
五、替代方案对比
| 方法 | 优点 | 缺点 |
|--------------------|-----------------------|-----------------------|
| /proc/stat解析 | 无需特权,精度高 | 需要自己计算差值 |
| sysinfo系统调用 | 接口简单 | 只能获取整体负载 |
| libstatgrab库 | 功能完整 | 需要额外依赖库 |
| cgroups接口 | 容器环境友好 | 配置复杂 |