线程使用率监控

有时候需要知道进程各个线程的CPU使用率,以平衡这些线程。

那怎么知道线程的CPU使用率呢?

以下是本人编写的类:

#ifndef _WZ_THREADCONTROL_H
#define _WZ_THREADCONTROL_H

 

struct ThreadInfo
{
 char szThreadName[15];
    HANDLE hThread;
 int nPercentCPUUsage;
 __int64 i64TimeStampLast;
 __int64 i64SystemTimeLast;
 DWORD dwThreadID;
 int nStatus;

};
enum ThreadControlStatus
{
 BeginScanThread = 0,
 AtScanThread = 1,
 EndScanThread = 2,
};
struct IThreadNotify
{
 virtual void Notify(int nStatus, ThreadInfo &ti) = 0;
};

class CWzThreadControl
{
public:
 static CWzThreadControl *Instant();
 static void Release();
 void AddThreadNotify(IThreadNotify* pThreadNotify);
 void DeleteThreadNotify(IThreadNotify *pThreadNotify);
 void Start(HANDLE hModule, DWORD dwModule);
 void End();

private:
 HWND m_hWnd;
 HANDLE m_hModuleCurrent;
 DWORD m_dwModuleCurrent;
    void* m_mapThreads;
 void* m_lstThreadNotify;
 CWzThreadControl();
 virtual ~CWzThreadControl();
 static CWzThreadControl *m_pWzThreadControl;
 static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
 void OnThreadInfoNotify(ThreadInfo &ti);
 void ScanThread();

};

 

#endif

 

 

#include "StdAfx.h"
#include "wzThreadControl.h"
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <map>
#include <list>
#include <algorithm>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CWzThreadControl *CWzThreadControl::m_pWzThreadControl = NULL;

 

#define DETECTTIMERID WM_USER + 101
CWzThreadControl::CWzThreadControl()
{
   m_mapThreads = (void*)new map<DWORD, ThreadInfo>;
   m_lstThreadNotify = (void*)new list<IThreadNotify*>;
   m_hModuleCurrent = NULL;
   m_dwModuleCurrent = -1;
   m_hWnd = NULL;

}

CWzThreadControl::~CWzThreadControl()
{

 if(m_mapThreads != NULL)
 {
  delete m_mapThreads;
  m_mapThreads = NULL;
 }
 if(m_lstThreadNotify != NULL)
 {
  delete m_lstThreadNotify;
  m_lstThreadNotify = NULL;
 }

}

LRESULT CALLBACK CWzThreadControl::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 
 if(CWzThreadControl::Instant()->m_hWnd == hwnd && msg == WM_TIMER)
 {
  CWzThreadControl::Instant()->ScanThread(); 
 }
 
 return DefWindowProc(hwnd, msg, wParam, lParam);
}

 

void CWzThreadControl::ScanThread()
{

 if(m_dwModuleCurrent == -1)
 {
  return;
 }
 DWORD dwProcessID = m_dwModuleCurrent;

 HANDLE        hThreadSnap = NULL;
 BOOL bRet = FALSE;
 THREADENTRY32 te32        = {0};
    ThreadInfo ti; 
 // Take a snapshot of all threads currently in the system.


 hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessID);
 if (hThreadSnap == INVALID_HANDLE_VALUE)
 {
  return;
 }
 
 // Fill in the size of the structure before using it.
 
 te32.dwSize = sizeof(THREADENTRY32);
 
 // Walk the thread snapshot to find all threads of the process.
 // If the thread belongs to the process, add its information
 // to the display list.
 bRet = Thread32First(hThreadSnap, &te32);
 HANDLE hThread = NULL;
    FILETIME CreationTime;
    FILETIME ExitTime;
    FILETIME KernelTime;
    FILETIME UserTime;
 while(bRet)
 { 

   if (te32.th32OwnerProcessID == dwProcessID)
  {
//    TRACE( "/nTID/t/t%d/n", te32.th32ThreadID);
//    TRACE( "Owner PID/t%d/n", te32.th32OwnerProcessID);
//    TRACE( "Delta Priority/t%d/n", te32.tpDeltaPri);
//          TRACE( "Base Priority/t%d/n", te32.tpBasePri);
   GetProcAddress(LoadLibrary("kernel32.dll"), "OpenThread");
   
   __asm
   {
    push te32.th32ThreadID
    push 0
    push THREAD_ALL_ACCESS
    call eax
    mov hThread,eax
   }
 
   GetThreadTimes(hThread, &CreationTime, &ExitTime,
    &KernelTime, &UserTime);

   __int64 i64Time = (KernelTime.dwHighDateTime << 32) + KernelTime.dwLowDateTime +
                  (UserTime.dwHighDateTime << 32) + UserTime.dwLowDateTime;
   map<DWORD, ThreadInfo> *pThread = (map<DWORD, ThreadInfo> *)m_mapThreads;  
   map<DWORD, ThreadInfo>::iterator itr = pThread->find(te32.th32ThreadID);
   if(itr != pThread->end())
   {
    ThreadInfo ti = itr->second;
    __int64 nCurTimestamp = ((__int64)GetTickCount() * 10000);

    if(ti.i64SystemTimeLast != 0)
    {
//     ASSERT(ti.i64TimeStampLast != 0);
     ti.nPercentCPUUsage = int(double(i64Time - ti.i64TimeStampLast) * 100.00 /
        double(nCurTimestamp - ti.i64SystemTimeLast)) / 2;
//      TRACE("nPercentCPUUsage = %d, Name = %s/n",
//       ti.nPercentCPUUsage,
//       ti.szThreadName);
    }

    ti.i64SystemTimeLast = nCurTimestamp;
    ti.i64TimeStampLast = i64Time;
    itr->second = ti;
    
   }
   else
   {
    ThreadInfo ti;
    ti.dwThreadID = te32.th32ThreadID;
    ti.i64SystemTimeLast = 0;
    ti.i64TimeStampLast = 0;
    memset(ti.szThreadName, 0, sizeof(ti.szThreadName));
    ti.hThread = hThread;
    ti.nPercentCPUUsage = 0;
    ti.nStatus = -1;
    (*pThread)[te32.th32ThreadID] = ti;
              
   }

//    for(map<HANDLE, ThreadInfo>::iterator itr = pThread->begin();
//    itr != pThread->end(); itr++)
//    {
//     ThreadInfo ti = itr->second;
//     if(ti.dwThreadID == te32.th32ThreadID)
//     {
// //      SYSTEMTIME syt;
// //      GetLocalTime(&syt);
// //      CTime tm(syt);
//
//      __int64 nCurTimestamp = ((__int64)GetTickCount() * 10000);
//
//      if(ti.i64SystemTimeLast != 0)
//      {
//       ASSERT(ti.i64TimeStampLast != 0);
//       ti.nPercentCPUUsage = int(double(i64Time - ti.i64TimeStampLast) * 100.00 /
//             double(nCurTimestamp - ti.i64SystemTimeLast)) / 2;
//       TRACE("nPercentCPUUsage = %d, Name = %s/n",
//        ti.nPercentCPUUsage,
//        ti.szThreadName);
//      }
//
//      ti.i64SystemTimeLast = nCurTimestamp;
//      ti.i64TimeStampLast = i64Time;
//      itr->second = ti;
//     }
//    }
//         TRACE( "UserTime %d,%d/n", KernelTime.dwHighDateTime, KernelTime.dwLowDateTime);
//   TRACE( "UserTime %d%d/n", i64Time); 
  }

  bRet = Thread32Next(hThreadSnap, &te32);

 }

 // Do not forget to clean up the snapshot object.
 
 CloseHandle (hThreadSnap);

 list<IThreadNotify*> *plstThreadNotify = (list<IThreadNotify*>*)m_lstThreadNotify;
 for (list<IThreadNotify*>::iterator itrThreadNotify = plstThreadNotify->begin();
 itrThreadNotify != plstThreadNotify->end(); itrThreadNotify++)
 {
  IThreadNotify* pThreadNotify = (*itrThreadNotify);
  if (pThreadNotify == NULL)
  {
   continue;
  }
  pThreadNotify->Notify(BeginScanThread, ti);
 }

 map<DWORD, ThreadInfo> *pThread = (map<DWORD, ThreadInfo> *)m_mapThreads; 
 for(map<DWORD, ThreadInfo>::iterator itr = pThread->begin();
 itr != pThread->end(); itr++)
 {
  ThreadInfo ti = itr->second;
        OnThreadInfoNotify(ti);
 } 

 for (itrThreadNotify = plstThreadNotify->begin();
 itrThreadNotify != plstThreadNotify->end(); itrThreadNotify++)
 {
  IThreadNotify* pThreadNotify = (*itrThreadNotify);
  if (pThreadNotify == NULL)
  {
   continue;
  }
  pThreadNotify->Notify(EndScanThread, ti);
 }
 return ;

}

void CWzThreadControl::OnThreadInfoNotify(ThreadInfo &ti)
{
 list<IThreadNotify*> *plstThreadNotify = (list<IThreadNotify*>*)m_lstThreadNotify;
 for (list<IThreadNotify*>::iterator itr = plstThreadNotify->begin();
 itr != plstThreadNotify->end(); itr++)
 {
  IThreadNotify* pThreadNotify = (*itr);
  if (pThreadNotify == NULL)
  {
   continue;
  }
  pThreadNotify->Notify(AtScanThread, ti);
 }
  TRACE("ThreadID = %d, PercentCPUUsage = %d/n", ti.dwThreadID, ti.nPercentCPUUsage);

}

void CWzThreadControl::AddThreadNotify(IThreadNotify* pThreadNotify)
{
 list<IThreadNotify*> *plstThreadNotify = (list<IThreadNotify*>*)m_lstThreadNotify;

 if (pThreadNotify != NULL)
 {
  plstThreadNotify->push_back(pThreadNotify);
 }
}
 
void CWzThreadControl::DeleteThreadNotify(IThreadNotify *pThreadNotify)
{
 list<IThreadNotify*> *plstThreadNotify = (list<IThreadNotify*>*)m_lstThreadNotify;
 if(pThreadNotify == NULL)
 {
  plstThreadNotify->clear();
  return;
 }
 
 list<IThreadNotify*>::iterator itr = find(plstThreadNotify->begin(), plstThreadNotify->end(), pThreadNotify);
 if (itr != plstThreadNotify->end())
 {
  plstThreadNotify->erase(itr);
 }
}

CWzThreadControl *CWzThreadControl::Instant()
{

 if(m_pWzThreadControl == NULL)
 {
  m_pWzThreadControl = new CWzThreadControl;

  WNDCLASSEX wc;
  wc.cbSize        = sizeof(WNDCLASSEX);
  wc.style         = 0;
  wc.lpfnWndProc   = WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = NULL;
  wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = "ThreadControl";
  wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
  
  if(!RegisterClassEx(&wc))
  {
   return 0;
  }
  
  m_pWzThreadControl->m_hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,
   "ThreadControl",
   "ThreadControl",
   WS_OVERLAPPEDWINDOW,
   CW_USEDEFAULT,
   CW_USEDEFAULT, 0, 0, NULL, NULL, NULL, NULL);
  
  if(m_pWzThreadControl->m_hWnd == NULL)
  {
   return 0;
  }
 }

 return m_pWzThreadControl;

}
 

void CWzThreadControl::Release()
{

 if(m_pWzThreadControl != NULL)
 {
  ::DestroyWindow(m_pWzThreadControl->m_hWnd);
  ::SendMessage(m_pWzThreadControl->m_hWnd, WM_CLOSE, 0, 0);

  m_pWzThreadControl->m_hWnd = NULL;
  delete m_pWzThreadControl;
  m_pWzThreadControl = NULL;

 }

}

void CWzThreadControl::Start(HANDLE hModule, DWORD dwModule)
{

 m_hModuleCurrent = hModule;
 m_dwModuleCurrent = dwModule;
    SetTimer(m_hWnd, DETECTTIMERID, 500, NULL);
}

void CWzThreadControl::End()
{
 KillTimer(m_hWnd, DETECTTIMERID);
    map<DWORD, ThreadInfo> *pThread = (map<DWORD, ThreadInfo> *)m_mapThreads; 
 pThread->clear();

}

 

 

1、知道了各个线程的CPU使用率后,可以对各个线程进行平衡,如果发现某个线程使用率太大,可以用SuspendThread暂停线程,以为其他模块交出时间片,用ResumnThread恢复执行。

2、同时可以在此基础上编写检测线程状态的功能,这对于检测死锁问题也有帮助,当发现死锁时马上解锁恢复执行。

3、有时虽然知道的线程ID,但不知道具体是那个线程,这可以在线程创建时,记录该线程和线程ID的对应关系以方便查找。但其实可以在进程中埋下标准接口,而由线程监控模块去获取线程和线程ID的对应关系,这样可以把线程监控模块做成另外一个进程(或者说另外一个工具)。用户使用该工具可以很明显看出那个线程ID对应哪个线程。

 

有什么问题请加我QQ:363169978(明白),欢迎打扰。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值