获取电脑实时CPU使用率

要求:实现一个计算电脑实时CPU占有率的测试程序,将多种方法获取结果显示在对话框上,动态显示。

实现:

1、新建基于对话框的MFC应用程序,Dialog上添加控件,为控件添加CSting类型变量m_RateResult1、m_RateResult2、m_RateResult3,

      

2、创建线程类(Thread.h和Thread.cpp),在 ####Dlg.cpp 文件中的初始化函数 OnInitDialog() 中创建计算CPU利用率的线程

    // TODO: 在此添加额外的初始化代码

    _beginthread(&CThread::InitCalcuPdh, 0, this);
    _beginthread(&CThread::InitCalcuGet, 0, this);
    _beginthread(&CThread::InitCalcuNt,  0, this);

3、线程类中计算CPU利用率

方式一:使用Performance Data Helper(PDH)性能数据助手,获取CPU利用率

 1 void CThread::InitCalcuPdh(void *pDlg)
 2 {
 3     CCalculateCPURateDlg *pItemDlg = (CCalculateCPURateDlg *)pDlg;
 4     if (pItemDlg == NULL)
 5     {
 6         return;
 7     }
 8 
 9     while(1)
10     {
11         //打开查询(query)句柄
12         HQUERY query;
13         PDH_STATUS status = PdhOpenQuery(NULL, NULL, &query);
14         if (status != ERROR_SUCCESS)
15         {
16             pItemDlg->MessageBox(L"Open Query Error", NULL, MB_OK);
17             continue;
18         }
19             
20         //在查询中加入计数器(counter)
21         HCOUNTER counter;
22         //counter = (HCOUNTER *)GlobalAlloc(GPTR, sizeof(HCOUNTER));
23         status = PdhAddCounter(query, LPCWSTR(L"\\Processor Information(_Total)\\% Processor Time"), NULL, &counter);
24         if (status != ERROR_SUCCESS)
25         {
26             pItemDlg->MessageBox(L"Add Counter Error", NULL, MB_OK);
27             continue;
28         }
29 
30         //收集query的数据,在两条PdhCollectQueryData()语句之间加入一条Sleep(1000)语句
31         PdhCollectQueryData(query);
32         Sleep(1000);
33         PdhCollectQueryData(query);
34 
35         //获得格式化(可以显示的)数据
36         PDH_FMT_COUNTERVALUE pdhValue;
37         DWORD dwValue;
38         status = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, &dwValue, &pdhValue);
39         if (status != ERROR_SUCCESS)
40         {
41             pItemDlg->MessageBox(L"Get Value Error", NULL, MB_OK);
42             continue;
43         }
44         pItemDlg->m_RateResult1.Format(L"%.0lf%%", pdhValue.doubleValue);
45 
46         SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE); 
47         PdhCloseQuery(query);
48     }
49 }

方式二:使用windows 自带的API(GetSystemTimes)获取CPU利用率

 1 __int64 DiffFileTime(FILETIME time1, FILETIME time2)
 2 {
 3     __int64 a = time1.dwHighDateTime << 32 | time1.dwLowDateTime;
 4     __int64 b = time2.dwHighDateTime << 32 | time2.dwLowDateTime;
 5     return (b - a);
 6 }
 7 void CThread::InitCalcuGet(void *pDlg)
 8 {
 9     CCalculateCPURateDlg *pItemDlg = (CCalculateCPURateDlg *)pDlg;
10     if (pItemDlg == NULL)
11     {
12         return;
13     }
14 
15     while(1)
16     {
17         double cpurate;
18         __int64 idle, kernel, user;
19         FILETIME preidleTime, idleTime;      //空闲时间
20         FILETIME prekernelTime, kernelTime;  //内核态时间
21         FILETIME preuserTime, userTime;      //用户态时间
22 
23         //计算CPU使用率,需要收集两份样本,中间用Sleep()函数间隔1s
24         GetSystemTimes(&preidleTime, &prekernelTime, &preuserTime);
25         Sleep(1000);
26         GetSystemTimes(&idleTime, &kernelTime, &userTime);
27 
28         idle = DiffFileTime(preidleTime, idleTime);
29         kernel = DiffFileTime(prekernelTime, kernelTime);
30         user = DiffFileTime(preuserTime, userTime);
31 
32         if (kernel + user == 0)
33             cpurate = 0.0;
34         else
35             cpurate = abs((kernel + user - idle) * 100 / (kernel + user));//(总的时间-空闲时间)/总的时间=占用cpu的时间就是使用率
36         
37         pItemDlg->m_RateResult2.Format(L"%.0lf%%", cpurate);
38         SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE); 
39     }
40 }

方式三:使用windows API(NtQuerySystemInformation)获取CPU利用率

 1 typedef struct _UINT64_DELTA
 2 {
 3     ULONG64 Value;
 4     ULONG64 Delta;
 5 } UINT64_DELTA, *PUINT64_DELTA;
 6 
 7 #define UpdateDelta(DltMgr, NewValue) \
 8 ((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \
 9 (DltMgr)->Value = (NewValue), (DltMgr)->Delta)
10 
11 void CThread::InitCalcuNt(void *pDlg)
12 {
13     CCalculateCPURateDlg *pItemDlg = (CCalculateCPURateDlg *)pDlg;
14     if (pItemDlg == NULL)
15     {
16         return;
17     }
18 
19     while(1)
20     {
21         double cpu_rate;
22         ULONG64 total_time = 0;
23         ULONG64 sys_time = 0;
24         static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION CpuInformation[1024];
25         static SYSTEM_INFO sys_info;
26 
27         static UINT64_DELTA cpu_kernel_delta;
28         static UINT64_DELTA cpu_user_delta;
29         static UINT64_DELTA cpu_idle_delta;
30         static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpu_totals;
31         memset(&cpu_totals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
32 
33         GetSystemInfo(&sys_info);
34 
35         NtQuerySystemInformation(
36             SystemProcessorPerformanceInformation,
37             &CpuInformation,
38             sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * (ULONG)sys_info.dwNumberOfProcessors,
39             NULL
40             );
41 
42         for (int i = 0; i < (int)sys_info.dwNumberOfProcessors; i++)
43         {
44             SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpu_info = CpuInformation[i];
45 
46             // KernelTime includes idle time.
47             LONGLONG dpc_time = cpu_info.Reserved1[0].QuadPart;
48             LONGLONG interrupt_time = cpu_info.Reserved1[i].QuadPart;
49             cpu_info.KernelTime.QuadPart -= cpu_info.IdleTime.QuadPart;
50             cpu_info.KernelTime.QuadPart += dpc_time + interrupt_time;
51 
52             cpu_totals.Reserved1[0].QuadPart += dpc_time;
53             cpu_totals.IdleTime.QuadPart += cpu_info.IdleTime.QuadPart;
54             cpu_totals.Reserved2 += cpu_info.Reserved2;
55             cpu_totals.Reserved1[1].QuadPart += cpu_info.Reserved1[1].QuadPart;
56             cpu_totals.KernelTime.QuadPart += cpu_info.KernelTime.QuadPart;
57             cpu_totals.UserTime.QuadPart += cpu_info.UserTime.QuadPart;
58         }
59 
60         UpdateDelta(&cpu_kernel_delta, cpu_totals.KernelTime.QuadPart);
61         UpdateDelta(&cpu_user_delta, cpu_totals.UserTime.QuadPart);
62         UpdateDelta(&cpu_idle_delta, cpu_totals.IdleTime.QuadPart);
63 
64         total_time = cpu_kernel_delta.Delta + cpu_user_delta.Delta + cpu_idle_delta.Delta;
65         sys_time = cpu_kernel_delta.Delta + cpu_user_delta.Delta;
66 
67         if (total_time)
68             cpu_rate = sys_time * 100.0 / total_time;
69         else
70             cpu_rate = 0.0;
71         pItemDlg->m_RateResult3.Format(L"%.0lf%%", cpu_rate);
72         Sleep(1000);
73 
74         SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE); 
75     }
76 }

4、stdafx.h 中添加

#pragma comment(lib,"pdh.lib")
#pragma comment(lib,"ntdll.lib")
#include <Pdh.h>
#include <PdhMsg.h>
#include <Windows.h> 
#include <Winternl.h>

 

 

错误:

1、在线程中调用UpdateData函数,在Debug模式下编译可以通过,但运行时会触发中断

原因:MFC对象不支持多线程操作,不能供多个线程进程使用。子线程调用pDlg-> UpdateData(FALSE)时主线程(界面线程)会阻塞,更新必须由它完成,这样就形成死锁。更改界面的操作最好用主线程(界面线程),要想在子线程(工作线程)里执行界面的操作,可以通过向主线程发送消息来解决。

解决:

####Dlg.h 中添加

#define WM_UPDATEDATA  10000+1

afx_msg LRESULT OnUpdateData(WPARAM wParam, LPARAM lParam);

####Dlg.cpp 中添加

ON_MESSAGE(WM_UPDATEDATA, OnUpdateData) 

LRESULT CCalculateCPURateDlg::OnUpdateData(WPARAM wParam, LPARAM lParam) 
{ 
    UpdateData(wParam); 
    return 0; 
} 

Thread.cpp 中添加

SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE);

2、在某些环境中exe文件运行失败

解决:Release使用MT选项编译,Debug使用MTd选项编译(同时属性页中选择在静态库中使用MFC)

 

参考博客:

https://www.cnblogs.com/einyboy/archive/2012/06/13/2548243.html

http://www.cnblogs.com/hbccdf/p/get_sys_cpu_usage_and_mem_usage.html

 

posted on 2018-12-10 19:18  Noora&w  阅读(4222)  评论(0编辑  收藏  举报