| 
				 五、蚂蚁线管理类 
蚂蚁线管理类(CMarchingAntsManager)实现蚂蚁线的生成、删除、绘制(蚂蚁爬动)、暂停、属性修改等功能。 
主要属性如表3所示。 
表3  蚂蚁线管理类属性 
| 
 HWND hWnd  | 
 窗口句柄  |  
| 
 ants_vector  | 
 蚂蚁线数组  |  
| 
 HANDLE  m_hThread  | 
 线程句柄  |  
| 
 HANDLE  m_hPause  | 
 暂停标志句柄  |  
| 
 HANDLE  m_hExitEvent  | 
 退出事件句柄  |  
| 
 bool        m_bIsInitialized  | 
 初始化标志  |  
| 
 bool        m_bPause  | 
 暂停标志  |  
| 
 CRITICAL_SECTION cs  | 
 互斥量  |  
| 
 bool     b_UseGdiplus  | 
 使用GDI或GDI++绘制  |    
主要方法如表4所示: 
表4 蚂蚁线管理类方法 
| 
 void Initialize()  | 
 初始化  |  
| 
 bool InitAnimation()  | 
 开始流动  |  
| 
 void SetPause(bool bPause)  | 
 是否暂停  |  
| 
 void Destroy()  | 
 删除  |  
| 
 void SetUseGdiplus(bool flag)  | 
 使用GDI++绘制标志  |  
| 
 void Delete()  | 
 删除数据  |  
| 
 bool Draw(void)  | 
 绘制  |  
| 
 void ThreadAnimation()  | 
 启动动画线程  |  
| 
 _ThreadAnimationProc(LPVOID)  | 
 动画线程  |    
除此之外,还提供了多种蚂蚁线的加入函数,如点(Point、Points)、线(Line、Lines)、矩形(Rectangle)等基本图形蚂蚁线函数,通过其返回指针可修改各种蚂蚁线的属性。多个蚂蚁线存放在ants_vector蚂蚁线数组中。 
1. 绘制线程 
由于同时需要绘制的蚂蚁线有多个,蚂蚁线的绘制放在线程中实现,比采用定时器实现有更好的封装,绘制过程用ThreadAnimation线程实现,其关键的代码在Draw中实现。主要代码如下: 
//对蚂蚁线数组进行循环 
    for(……) 
    { 
        if(*iter) 
        { 
            if(b_UseGdiplus)//采用GDI++进行绘制 
            { 
//构造绘图对象 
                Graphics graphics(hWnd); 
                  //调用具体蚂蚁线绘制功能 
                (*iter)->Draw(&graphics); 
            } 
            else//采用GDI进行绘制 
            { 
                  //得到绘图句柄 
                HDC hDC=GetDC(hWnd); 
                  //调用具体蚂蚁线绘制功能 
                 (*iter)->Draw(hDC); 
                  //释放绘图句柄 
                ReleaseDC(hWnd,hDC); 
            } 
        } 
    } 
从这里看出,在各类蚂蚁线中实现了具体的绘制过程,管理起来就很容易,充分体现了C++重载的好处。 
2.线程同步 
由于采用了线程绘制蚂蚁线,同时还需要动态增加、删除蚂蚁线、修改蚂蚁线的属性、启动、退出等功能,这就涉及到线程同步问题,处理不好会出现不可预知的错误。 
线程同步是多线程程序设计的核心内容,其目的是正确处理多线程并发时的各种问题,例如线程的等待、多个线程访问同一数据时的互斥,防死锁等。Win32提供多种内核对象和手段用于线程同步,如互斥量、信号量、事件、临界区等。所不同的是,互斥量、信号量、事件都是Windows的内核对象,当程序对这些对象进行控制时会自动转换到核心态,而临界区本身不是内核对象,它是工作在用户态的。从用户态转换到核心态是需要以时间为代价的,所以如果能在用户态就简单解决的问题,就可以不必劳烦核心态了。 
临界区保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后,其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。  
临界区包含两个操作原语: 
EnterCriticalSection() 进入临界区 
LeaveCriticalSection()离开临界区 
EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。 
在蚂蚁线实现的过程中,在访问数据时进行时都进行了以上操作,如修改蚂蚁线宽度的SetWidth()方法的实现: 
void CMarchingAntsType::SetWidth(unsigned int w) 
{ 
    EnterCriticalSection(&cs); 
    width=w; 
    LeaveCriticalSection(&cs); 
} 
线程的退出同步主要是通过信号事件实现,初始化时实现代码如下: 
void CMarchingAntsManager::Initialize() 
{ 
    m_hThread = NULL; 
    m_bIsInitialized = false; 
     
    m_bPause = false; 
     //创建退出事件 
    m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,…); 
    //创建暂停事件 
m_hPause = CreateEvent(NULL,TRUE,TRUE,NULL); 
} 
退出时必须进行线程等待,主要代码如下: 
void CMarchingAntsManager::Destroy() 
{    
    if (m_hThread) 
    { 
        //如果是暂停,则停止暂停 
        SetPause(false); 
        SetEvent(m_hExitEvent); 
     //等待绘制线程退出 
        WaitForSingleObject(m_hThread, INFINITE); 
    } 
    //关闭相关句柄 
CloseHandle(m_hThread); 
    …… 
} 
    通过以上处理,程序运行稳定可靠。 
六、结语 
  虽然以上只实现了简单图形的蚂蚁线,但通过对CMarchingAntsType及相关继承类进行继承、重载绘制函数,可实现如椭圆、曲线等更加复杂蚂蚁线,实现的关键主要是将复杂图形进行离散化成折线,如对椭圆利用DDA算法、曲线可利用样条曲线生成算法,然后调用CMarchingAntsPolyLine的绘制方法即可实现各种复杂的蚂蚁线。 
  
参考资料 
  
[1]TroyHailey:TdhMarchingAnts[EB/OL],http://www.codeproject.com/KB/miscctrl/TdhMarchingAnts.aspx. 
[2]Dimitri van Heesch:doxygen[EB/OL], http://www.stack.nl/~dimitri/doxygen/. 
[3]Nicolai M.Josuttis,C++标准程序库[M],武汉华中科技大学出版社,2002 			
				 |