构建结构良好的多线程模型 第一章 构建模型 通俗地讲,多线程就好比多个人同时完成不同的任务,如果只有一个人,那就是单线程,任务只能一项接一项地完成,现在有多个人,你可以同时分配给他们不同的任务,每个人可以互不影响的同时进行任务,当然前提得分配合理。我们一般遇到的情况是人不可能随意更换,但任务却是五花八门都有,无论何种任务,都得去完成。 所以在本模型中,线程类只有一个“CThread”,但提供了一个任务接口“ITask”去适配各种各样的任务。 现实中,多个人同时完成不同的任务时,将可能出现以下几种情况: 一、每个人分到的任务都不同,互不冲突,这是本模型的基础。 二、同一项任务分给了几个人,这几个人之间针对任务相关资源会产生冲突,在本模型中通过在任务中加入互斥体解决,其中一个人进行任务时持有互斥体,其他人只能等待持有互斥体的人完成任务后释放互斥体,才有机会抢到互斥体开始任务,也就是同一时刻只能有一个人在任务中。 三、同一个人分到多项任务,对于这个人来说只能一项接一项地完成。对这种情况的支持有点复杂,在线程中用到了std::queue 队列数据结构,queue 是一个线性存储结构,只能在一端插入数据元素,在另一端删除,从而构成了一个先进先出FIFO(First In First Out)表。插入一端称为队尾,删除一端称为队首。 每分到一项任务时,从队尾插入,并判断前一项任务是否已完成,如果已完成,直接开始本项任务,否则等待直到前一项任务完成后才开始。完成的任务从队首删除。 MThread.h文件清单 //--------------------------------------------------------------------------- #ifndef MThreadH #define MThreadH //--------------------------------------------------------------------------- #include<windows.h> #include<process.h> #include<string> #include<queue> #include"DECLARE_ENUM.h" namespace MThread { class CCriticalSectionUser { public: class CCriticalSection { public: CCriticalSection(){::InitializeCriticalSection(&m_cs);} ~CCriticalSection(){:  eleteCriticalSection(&m_cs);} private: CCriticalSection(const CCriticalSection& src); CCriticalSection& operator=(constCCriticalSection& src); CRITICAL_SECTION m_cs; friend class CCriticalSectionUser; }; CCriticalSectionUser(CCriticalSection& CriticalSection) { m_pCCriticalSection=&CriticalSection; ::EnterCriticalSection(&m_pCCriticalSection->m_cs); } ~CCriticalSectionUser() { :  eaveCriticalSection(&m_pCCriticalSection->m_cs); m_pCCriticalSection=NULL; } private: CCriticalSectionUser(); CCriticalSectionUser(const CCriticalSectionUser& src); CCriticalSectionUser& operator=(const CCriticalSectionUser&src); CCriticalSection* m_pCCriticalSection; }; #define WAIT_MAX_COUNT 32 class ITask { public: ITask(const std::string&Name):m_Name(Name),m_hMutex(::CreateMutex(NULL,false,NULL)){} virtual ~ITask()=0; virtual void DoSomething()=0;//通过重载这个虚函数完成各种各样的任务 void Begin()const{::WaitForSingleObject(m_hMutex, INFINITE);} void End()const{::ReleaseMutex(m_hMutex);} const std::string& Name()const{return m_Name;} std::string& Name(){return m_Name;} protected: std::string m_Name; private: HANDLE m_hMutex; }; class CThread { private: static unsigned long c_ObjectCount; //对象计数 friend unsigned long __stdcall ThreadFunction(void*p); public: DECLARE_ENUM(THREAD_STATUS) { RUNNING, PAUSE, STOP, }END_ENUM() public: CThread():m_ID(c_ObjectCount++){} ~CThread() { c_ObjectCount--; while(!m_ThreadQueue.empty()) { if(m_ThreadQueue.front()->m_bFinish) { deletem_ThreadQueue.front(); m_ThreadQueue.pop(); }else{ //关闭还没完成任务的线程 ::TerminateThread(m_ThreadQueue.front()->m_hThread,0); m_ThreadQueue.front()->m_bFinish=true; } } } void Start(ITask& Task) { if(!m_ThreadQueue.empty()) { while(!m_ThreadQueue.empty()) { if(m_ThreadQueue.front()->m_bFinish) { deletem_ThreadQueue.front(); m_ThreadQueue.pop(); }else{ break; } } } THREAD_BODY* pThreadBody=new THREAD_BODY(); pThreadBody->m_pTask=&Task; if(!m_ThreadQueue.empty())pThreadBody->m_hPreThread=m_ThreadQueue.back()->m_hThread; //pThreadBody->m_hThread=(HANDLE)::_beginthreadex(NULL, 0,ThreadFunction, (void*)pThreadBody, 0, &pThreadBody->m_ThreadID); pThreadBody->m_hThread=(HANDLE)::CreateThread(NULL, 0,ThreadFunction, (void*)pThreadBody, 0, &pThreadBody->m_ThreadID); m_ThreadQueue.push(pThreadBody); } unsigned ID()const{return m_ID;} private: class THREAD_BODY { public: HANDLE m_hThread; unsigned long m_ThreadID; HANDLE m_hPreThread; ITask* m_pTask; bool m_bFinish; public: THREAD_BODY():m_hThread(NULL),m_ThreadID(0),m_hPreThread(NULL),m_pTask(NULL),m_bFinish(false){} ~THREAD_BODY(){if(NULL!=m_hThread)::CloseHandle(m_hThread);} }; std::queue<THREAD_BODY*> m_ThreadQueue; unsigned long m_ID; }; unsigned long __stdcall ThreadFunction(void*p) { CThread::THREAD_BODY* pThreadBody=(CThread::THREAD_BODY*)p; if(NULL!=pThreadBody) { if(NULL!=pThreadBody->m_hPreThread)::WaitForSingleObject(pThreadBody->m_hPreThread,INFINITE); if(NULL!=pThreadBody->m_pTask) { pThreadBody->m_pTask->Begin(); pThreadBody->m_pTask->DoSomething(); pThreadBody->m_pTask->End(); } pThreadBody->m_bFinish=true; } return 0; } }; #endif MThread.cpp文件清单 //--------------------------------------------------------------------------- #pragma hdrstop #include "MThread.h" //--------------------------------------------------------------------------- #pragma package(smart_init) using namespace MThread; ITask::~ITask(){::CloseHandle(m_hMutex);} unsigned longCThread::c_ObjectCount=0; //对象计数 第二章 应用例程 这是用C++Builder构建的例程,用C++Builder新建一个“应用程序”工程,把上述文件放在工程文件夹下,在窗体上放一个Button控件,一个Label控件,如 图1。 图1 在Unit1.cpp中键入以下代码。 //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "MThread.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //临界区对象 MThread::CCriticalSectionUser::CCriticalSectiong_cs; int g_index=0; class WorkerA: public MThread::ITask { public: int v; public: WorkerA(const std::string& Name):MThread::ITask(Name),v(0){} virtual void DoSomething() { // 进入临界区 { //CCriticalSectionUser csu(g_cs); // 对共享资源进行写入操作 for(int i=0;i<60;i++) { v++; g_index++; Form1->Label1->Caption=AnsiString("任务:")+this->Name().c_str()+",第"+IntToStr(v)+"步,索引值为:"+IntToStr(g_index); Sleep(300); } // 块结束离开临界区 } } }wa("wa"); class WorkerB: public MThread::ITask { public: int v; public: WorkerB(const std::string& Name):MThread::ITask(Name),v(0){} virtual void DoSomething() { // 进入临界区 { //CCriticalSectionUser csu(g_cs); // 对共享资源进行写入操作 for(int i=0;i<60;i++) { v++; g_index--; Form1->Label1->Caption=AnsiString("任务:")+this->Name().c_str()+",第"+IntToStr(v)+"步,索引值为:"+IntToStr(g_index); Sleep(300); } // 块结束离开临界区 } } }wb("wb"); MThread::CThread thread[2]; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent*Owner) :TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject*Sender) { thread[0].Start(wa); thread[1].Start(wb); } //--------------------------------------------------------------------------- 请大家注意void __fastcallTForm1::Button1Click(TObject *Sender){}中的代码: thread[0].Start(wa); thread[1].Start(wb); 代表上述第一种情况。 thread[0].Start(wa); thread[1].Start(wa); 代表上述第二种情况。 thread[0].Start(wa); thread[0].Start(wb); 代表上述第三种情况。请大家分别实验。
|