游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2382|回复: 0

构建结构良好的多线程模型

[复制链接]

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
发表于 2013-4-14 21:53:06 | 显示全部楼层 |阅读模式
构建结构良好的多线程模型
第一章 构建模型
通俗地讲,多线程就好比多个人同时完成不同的任务,如果只有一个人,那就是单线程,任务只能一项接一项地完成,现在有多个人,你可以同时分配给他们不同的任务,每个人可以互不影响的同时进行任务,当然前提得分配合理。我们一般遇到的情况是人不可能随意更换,但任务却是五花八门都有,无论何种任务,都得去完成。
所以在本模型中,线程类只有一个“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.JPG
图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);
代表上述第三种情况。请大家分别实验。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-2-26 23:19

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表