CSDN博客

img oldboy1234

模拟自主运行的对象(live object)

发表于2004/9/18 10:09:00  577人阅读

  C++提供了封装对象的方法,但是没有提供多线程的支持,如果需要产生多个同时自主运行的对象(live-object),就需要定义我们自己的多线程类。MSDN中的《Using Multithreading and C++ to Generate Live Objects》对这个有趣的技术进行了详细的介绍。

       废话少说,先来看一下产生一个支持多线程类的结构,下面以animate_object为例,先看一下animate_object的构造函数:

animated_object::animated_object(LPSTR lpImageName, short sType)
{
  < Initialize some member variables here. >
  hThread = CreateThread(NULL,
                         0,
                        (LPTHREAD_START_ROUTINE)ObjectThreadRoutine,
                         this,
                         0,
                        (LPDWORD)&this->dwIDThread);
  iStatus = (hThread != (HANDLE)NULL);
};

可以看到,在构造函数中产生了一个线程,hThread, 用于表示该对象所联系的对象,并且用iStatus表示是否成功产生了该线程,其中hThread作为private成员,其并不为外界所知,外部环境获得该对象的信息的唯一方式就是通过iStatus,这样实现了数据的封装,而且iStatus还可以用于表示所有初始化工作的成功或者失败

       下面是线程函数。由于线程函数不能够是非静态成员函数,所以需要使用一个全局函数

long WINAPI ObjectThreadRoutine(animated_object *fpObj)
{ 
 return (fpObj->MoveAndDraw());
} 

该全局函数实际上是一个stub function, 在函数内部调用了animated_object 对象的成员函数MoveAndDraw,为了让该全局函数可以使用animated_object的私有函数,需要将该全局函数声明为animated_object的友员函数。

       下面是析构函数

         animated_object::~animated_object(void)
{
  if (iStatus)
  {
   WaitForSingleObject(hThread,INFINITE);
   CloseHandle(hThread);
  };
  DeleteObject(hImage);
  MessageBeep(-1);
}; 

当对象析构的时候,在析构函数内部等待线程结束,然后关闭线程,注意只有当初始化成功(iStatus0)的时候,才会调用这些cleanup的工作,现在唯一的问题就是:如果该线程自己调用析构函数,就会产生死锁(A调用BB返回的条件是A已经结束),这里可以采用postMessage的方式,特别要注意的是如果使用sendMessage,仍然会产生死锁(可以用共享变量的方法避免死锁)关闭的方式,在线程函数中使用postMessage将关闭自己的消息发送给外部控制线程,由外部控制线程关闭线程,这样在调用析构函数的时候就不会产生死锁的问题了。

       同步问题:当产生多个该类的实例的时候,如果需要访问共享变量,需要使用互斥同步的方法,下面是animated_object的核心部分

long animated_object::MoveAndDraw(void)
{ int iTempX, iTempY;
  HDC hDC;
  while(!bFinished)
    {
      iTempX = iX+iXVelocity;
      iTempY = iY+iYVelocity;
 
/* The next four IF statements check whether a wall has been hit after a move.
   If yes, the position is reset to the wall, the direction reversed,
   and a random value added. */
 
< Wall-collison detection code follows here... */  
 
      EnterCriticalSection(&csSerializeDraw);
      hDC=GetDC(the_pond->hWndApplication);
 
< Erase the old image from the screen: >
 
      BitBlt(hDC,iX,iY,iImageWidth,iImageHeight,NULL,0,0,WHITENESS);
      iX = iTempX;
      iY = iTempY;
      iCalories-=MOVE_DEDUCTION;
 
/* Do three things here to determine whether one has died:  */
/* (a) Do additional per-move work, depending on the object type. */
/* (b) Determine whether we have enough fuel left to survive. */
/* (c) Ask the pond whether a collision has occurred. */
 
      if (!ObjectSpecificThreadRoutine(hDC) ||    // LOOK HERE!
          iCalories < 0 ||
          !the_pond->NewCoordinates(iHandle,iX,iY))
        bFinished=TRUE;
      else
/* Redraw the object. */
 
< Redraw code is in here.>
 
      ReleaseDC(the_pond->hWndApplication,hDC);
      LeaveCriticalSection(&csSerializeDraw);
/* Delay the object before moving on. */
      Sleep(DELAY);
    };   // end of while loop. Going past here means we are dead...
/* Inform the window that the thread has terminated, so it can clean up the object. */
 
  PostMessage(the_pond->hWndApplication,WM_OBJECT_DIED,(WPARAM)iHandle,NULL);
  return(TRUE);
};

       结论:通过使用C++的封装特性和多线程,可以很好的模拟live object,其他复杂的应用也可以通过这种方式进行扩展,可以模拟bolzman机这种需要同步运行的程序,并且作为并行程序在多CPU环境下“真正”的并行。

0 0

相关博文

我的热门文章

img
取 消
img