操作系统与网络 2019-3-8

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;
	// ================任务队列================
};

猜你喜欢

转载自blog.csdn.net/weixin_42896619/article/details/88431006