五、蚂蚁线管理类
蚂蚁线管理类(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
|