环境:win10+VS2017
网上找了几个demo发现CPU占用率不准确,跟任务管理器不一样。最后参考github项目GitHub - zhongyang219/TrafficMonitor: 这是一个用于显示当前网速、CPU及内存利用率的桌面悬浮窗软件,并支持任务栏显示,支持更换皮肤。,能过获取比较准确的CPU占用率。
注意要一秒获取一次CPU占用率,时间太短就不准确了。
WinVersionHelper.h
#pragma once
#define g_winVerHelper CWinVersionHelper::instance()
class CWinVersionHelper
{
public:
static CWinVersionHelper& instance();
CWinVersionHelper();
~CWinVersionHelper();
bool IsWindows10FallCreatorOrLater() const; // 判断当前Windows版本是否为Win10秋季创意者更新或更新的版本
bool IsWindows7() const; // 判断Windows版本是否为Windows7
bool IsWindows8Or8point1() const; // 判断Windows版本是否为Windows8或Windows8.1
bool IsWindows8OrLater() const;
bool IsWindows10OrLater() const;
int GetMajorVersion() const { return m_major_version; }
int GetMinorVersion() const { return m_minor_version; }
int GetBuildNumber() const { return m_build_number; }
protected:
int m_major_version{};
int m_minor_version{};
int m_build_number{};
};
WinVersionHelper.cpp
#include "WinVersionHelper.h"
#include <Windows.h>
CWinVersionHelper& CWinVersionHelper::instance()
{
static CWinVersionHelper s_instance;
return s_instance;
}
CWinVersionHelper::CWinVersionHelper()
{
DWORD dwMajorVer{}, dwMinorVer{}, dwBuildNumber{};
HMODULE hModNtdll{};
if (hModNtdll = ::LoadLibraryW(L"ntdll.dll"))
{
typedef void (WINAPI *pfRTLGETNTVERSIONNUMBERS)(DWORD*, DWORD*, DWORD*);
pfRTLGETNTVERSIONNUMBERS pfRtlGetNtVersionNumbers;
pfRtlGetNtVersionNumbers = (pfRTLGETNTVERSIONNUMBERS)::GetProcAddress(hModNtdll, "RtlGetNtVersionNumbers");
if (pfRtlGetNtVersionNumbers)
{
pfRtlGetNtVersionNumbers(&dwMajorVer, &dwMinorVer, &dwBuildNumber);
dwBuildNumber &= 0x0ffff;
}
::FreeLibrary(hModNtdll);
hModNtdll = NULL;
}
m_major_version = dwMajorVer;
m_minor_version = dwMinorVer;
m_build_number = dwBuildNumber;
}
CWinVersionHelper::~CWinVersionHelper()
{
}
bool CWinVersionHelper::IsWindows10FallCreatorOrLater() const
{
if (m_major_version > 10)
return true;
else if (m_major_version == 10 && m_minor_version > 0)
return true;
else if (m_major_version == 10 && m_minor_version == 0 && m_build_number >= 16299)
return true;
else return false;
}
bool CWinVersionHelper::IsWindows7() const
{
return (m_major_version == 6 && m_minor_version == 1);
}
bool CWinVersionHelper::IsWindows8Or8point1() const
{
return (m_major_version == 6 && m_minor_version > 1);
}
bool CWinVersionHelper::IsWindows8OrLater() const
{
if (m_major_version > 6)
return true;
else if (m_major_version == 6 && m_minor_version >= 2)
return true;
else return false;
}
bool CWinVersionHelper::IsWindows10OrLater() const
{
return m_major_version >= 10;
}
CCPUUsage.h:
#pragma once
#include <Pdh.h>
#include <PdhMsg.h>
#pragma comment(lib,"pdh.lib")
class CCPUUsage
{
public:
CCPUUsage()
{}
~CCPUUsage()
{}
void SetUseCPUTimes(bool use_get_system_times); //设置获取CPU利用率的方式,是通过GetSystemTimes还是Pdh
int GetCPUUsage();
private:
//int GetCPUUsageByGetSystemTimes();
int GetCPUUsageByPdh();
private:
bool m_use_get_system_times{ true }; //是否使用GetSysTime这个API来获取CPU利用率
PDH_RAW_COUNTER m_last_rawData;//保存计算CPU使用率的上一次数据
bool m_first_get_CPU_utility{ true };
FILETIME m_preidleTime{};
FILETIME m_prekernelTime{};
FILETIME m_preuserTime{};
};
CCPUUsage.cpp:
#if 1
#include "CPUUsage.h"
#include "WinVersionHelper.h"
#include <iostream>
using namespace std;
void CCPUUsage::SetUseCPUTimes(bool use_get_system_times)
{
if (m_use_get_system_times != use_get_system_times)
{
m_use_get_system_times = use_get_system_times;
m_first_get_CPU_utility = true;
}
}
int CCPUUsage::GetCPUUsage()
{
//if (m_use_get_system_times)
// return GetCPUUsageByGetSystemTimes();
//else
return GetCPUUsageByPdh();
}
#if 0
int CCPUUsage::GetCPUUsageByGetSystemTimes()
{
int cpu_usage{};
FILETIME idleTime;
FILETIME kernelTime;
FILETIME userTime;
GetSystemTimes(&idleTime, &kernelTime, &userTime);
__int64 idle = CCommon::CompareFileTime2(m_preidleTime, idleTime);
__int64 kernel = CCommon::CompareFileTime2(m_prekernelTime, kernelTime);
__int64 user = CCommon::CompareFileTime2(m_preuserTime, userTime);
if (kernel + user == 0)
{
cpu_usage = 0;
}
else
{
//(总的时间-空闲时间)/总的时间=占用cpu的时间就是使用率
cpu_usage = static_cast<int>(abs((kernel + user - idle) * 100 / (kernel + user)));
}
m_preidleTime = idleTime;
m_prekernelTime = kernelTime;
m_preuserTime = userTime;
return cpu_usage;
}
#endif
#include <iostream>
using namespace std;
int CCPUUsage::GetCPUUsageByPdh()
{
int cpu_usage{};
HQUERY hQuery;
HCOUNTER hCounter;
DWORD counterType;
PDH_RAW_COUNTER rawData;
PdhOpenQuery(NULL, 0, &hQuery);//开始查询
const wchar_t* query_str{};
if (g_winVerHelper.GetMajorVersion() >= 10)
query_str = L"\\Processor Information(_Total)\\% Processor Utility";
else
query_str = L"\\Processor Information(_Total)\\% Processor Time";
PdhAddCounter(hQuery, query_str, NULL, &hCounter);
PdhCollectQueryData(hQuery);
PdhGetRawCounterValue(hCounter, &counterType, &rawData);
if (m_first_get_CPU_utility) {//需要获得两次数据才能计算CPU使用率
cpu_usage = 0;
m_first_get_CPU_utility = false;
}
else {
PDH_FMT_COUNTERVALUE fmtValue;
PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_DOUBLE, &rawData, &m_last_rawData, &fmtValue);//计算使用率
cpu_usage = fmtValue.doubleValue;//传出数据
if (cpu_usage > 100)
cpu_usage = 100;
}
m_last_rawData = rawData;//保存上一次数据
PdhCloseQuery(hQuery);//关闭查询
return cpu_usage;
}
#endif
main.cpp
#include "CPUUsage.h"
#include <iostream>
using namespace std;
int main() {
CCPUUsage cpuUsage;
cpuUsage.SetUseCPUTimes(false);
while (1) {
cout << cpuUsage.GetCPUUsage() << endl;
Sleep(1000);
}
}