1.继续用线程重写任务管理器(游戏修改器)
1.1 在 CModifyMemory 类的构造函数中初始化
1.首先初始化线程数组的空间: ::ZeroMemory(m_hThread, sizeof(HANDLE)*4) ;
2.退出线程标记初始为true: m_bQuitThread = true ;
3.是否是第一次查找初始为true: m_bFindFirstOrNot = true ;
4.创建信号量: m_hSemaphore = ::CreateSemaphore(0, 0, 4, 0) ;
5.循环创建线程句柄(其实创建句柄的代码应该放到初始化函数中);
CModifyMemory::CModifyMemory(void)
{
m_hOpenPracess = 0;
//=====================线程处理========================
::ZeroMemory(m_hThread, sizeof(HANDLE)*4);
m_bQuitThread = true;
m_bFindFirstOrNot = true;
m_hSemaphore = ::CreateSemaphore(0, 0, 4, 0); // 信号量
if(m_hSemaphore == 0)
::MessageBox(0, _T("创建信号量失败"), _T("提示"), MB_OK);
for(int i=0; i<4; i++)
{
m_hThread[i] = ::CreateThread(0, 0, &CModifyMemory::ThreadProc, this, 0, 0);
if(m_hThread[i] == 0)
::MessageBox(0, _T("创建线程失败"), _T("提示"), MB_OK);
}
//=====================线程处理========================
}
1.2 在析构函数中关闭线程相关的句柄
1.改变线程退出标志: m_bQuitThread = false ;
2.循环删除线程句柄;
3.关闭信号量句柄: ::CloseHandle(m_hSemaphore) ; m_hSemaphore = 0 ;
CModifyMemory::~CModifyMemory(void)
{
//==================================线程删除=================================
m_bQuitThread = false;
for(int i=0; i<4; i++)
{
if(::WaitForSingleObject(m_hThread[i], 10) == WAIT_TIMEOUT)
::TerminateThread(m_hThread[i], -1);
::CloseHandle(m_hThread[i]);
m_hThread[i] = 0;
}
::CloseHandle(m_hSemaphore);
m_hSemaphore = 0;
//==================================线程删除=================================
... ...
}
1.3 将第一次查找的代码放到线程处理函数中
1.将开始查找的起始地址、终止地址以及一页的大小变成成员变量放到类 CModifyMemory 中,并在构造中初始化: dw_begin_addr = 64 * 1024 , dw_end_addr = (ULONG)(2UL * 1024UL * 1024UL * 1024UL) , dw_one_page = 4096 ;
2.在线程处理函数中先等信号量的到来,再判断是第几次查找,若是第一次查找则在内存中进行查找;若是第二次查找,则我们在链表中查找,但是由于链表的长度不会太大,因此我们不需要再写一遍;
// 线程处理函数
DWORD WINAPI CModifyMemory::ThreadProc(LPVOID lpParamter)
{
CModifyMemory* pThis = (CModifyMemory*)lpParamter;
while (pThis->m_bQuitThread)
{
// 等信号
if(::WaitForSingleObject(pThis->m_hSemaphore, 10) == WAIT_TIMEOUT)
continue;
if(pThis->m_bFindFirstOrNot)
{
while (pThis->m_bQuitThread)
{
DWORD dw_TempBeginAddr = 0;
// ====================一页一页查找=====================
pThis->m_lcAddr.MyLock();
if(dw_begin_addr > dw_end_addr)
break;
dw_TempBeginAddr = dw_begin_addr;
dw_begin_addr += dw_one_page;
pThis->m_lcAddr.MyUnlock();
// ====================一页一页查找=====================
pThis->FindOnePage(dw_begin_addr, pThis->m_dwFindValue);
}
}
else
{
}
}
return 0;
}
1.4 在读取一页的函数 FindOnePage 中进行修改
1.因为多个线程可能同时用到装地址的链表,因此我们对其进行加旋转锁;
2.在得到地址后,我们自定义一个消息用来给主窗口发这个消息,让主窗口来对对话框进行操作;
// 读取一页的内容
void CModifyMemory::FindOnePage(DWORD dwPageBeginAddr, DWORD nFindValue)
{
// 用一个数组来存储读到的内容
DWORD sz_buffer[1024] = {0};
// 读进程地址空间的内容
// 读取失败则返回
if(0 == ::ReadProcessMemory(m_hOpenPracess, (LPCVOID)dwPageBeginAddr, (LPVOID)sz_buffer, 4096, 0))
return;
// 读取成功则查找偏移量
for(int i=0; i<1024; i++)
{
if(sz_buffer[i] == nFindValue)
{
// 将其地址插入到链表中
DWORD dw_addr = 0;
this->m_lcList.MyLock();
dw_addr = dwPageBeginAddr + i*4;
m_lst_addr.push_back(dw_addr);
this->m_lcList.MyUnlock();
// 通知主窗口
::PostThreadMessage(theApp.m_nThreadID, UM_THREAD_TO_MAIN, dw_addr, 0);
}
}
}
1.5 小结
1.通过多个多线程的例子,我们发现:在使用多线程的工作中,只要见到共享变量,我们就需要给其加锁;
2.线程池
2.1 一个计算机可以创建的最大线程数为:cpu*2
2.2 进程池中有任务队列
2.3 新建一个Win32控制台应用程序
1.创建一个 CMyThreadPool 类,其中包括旋转锁的类 CMyLock ,一个任务类 CTask 类(其中包括一个虚析构和一个纯虚函数 RunTask );
2.在 CMyThreadPool 类中添加成员;
#pragma once
#include <windows.h>
#include <queue>
using namespace std;
// 任务类
class CTask
{
public:
virtual ~CTask(){}
virtual void RunTask()=0;
};
// 旋转锁类
class CMyLock
{
private:
CRITICAL_SECTION cs;
public:
CMyLock()
{
::InitializeCriticalSection(&cs);
}
~CMyLock()
{
::DeleteCriticalSection(&cs);
}
void MyLock()
{
::EnterCriticalSection(&cs);
}
void MyUnlock()
{
::LeaveCriticalSection(&cs);
}
};
// 主类
class CMyThreadPool
{
public:
CMyThreadPool(void);
~CMyThreadPool(void);
private:
// ===============控制线程个数===============
DWORD m_dwMinThreadCount;
DWORD m_dwMaxThreadCount;
DWORD m_dwCurrentThreadCount;
DWORD m_dwRunThreadCount;
// ===============控制线程个数===============
// ===============控制线程==============
list<HANDLE> m_lsThread;
bool m_bQuitThread;
// ===============控制线程==============
// ===============同步方式================
HANDLE m_hSemaphoreRun;
CMyLock m_lockList;
// ===============同步方式================
// ================任务队列================
queue<CTask*> m_quTask;
// ================任务队列================
};