Thread: Threads in MFC

  1. #1
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607

    Threads in MFC

    How do you create threads that must contain loops w/o using 99% of the CPU for your process?

    For instance, I need to constantly monitor the state of animations in my editor. Each animation is it's own thread and updates itself. As soon as the first thread fires, the CPU usage on the task manager shoots up to 100%. I have no idea how to implement the thread so that it does not have to loop, but if it terminates then I must re-create the thread and well that sort of defeats the purpose.

    Any ideas? Should I fire off a completely new process or use threads?

  2. #2
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    From what you describe you have two possible ways of implementing it: polling or event based. If you use polling, you will use a loop in your monitoring thread that will eat 100% CPU. You can put some sleeps in but it will only become unresponsive if you sleep it long enough in between checks.

    The other way would be event based.

    Create an event that both your monitoring thread and your animation editing thread can access. Let your monitoring thread WaitForSingleObject for that event. The animation thread can manually fire the event when it's done with the changes so the monitoring thread will then wake, do it's task and ( if you loop it ) return to it's former waiting state at 0% CPU.

    CreateThread
    CreateEvent
    WaitForSingleObject

    might be valuable starters. There are MFC encapsulation classes for those calls, but I prefer to use them raw.
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  3. #3
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Will try this. Thanks.

    The mechanism I'm using updates itself. The thread function monitors the time that has elapsed since the thread last executed it's task. So the thread is responsible for updating it's time deltas relative to it's animation. So if I sleep() inside of the thread, the updating will still work correctly. If I attempt to do this externally or wait for a lock or unlock condition the time deltas will not be correct since the time is retrieved at the beginning of the thread task and immediately after.

    Why'd they have to make it so hard?

    Portion of CAnimSystem.h
    Code:
    class CAnimSequence
    {
      //Container class friend
      friend class CAnimSequenceContainer;
    
      //vector of CAnimFrames (not included in this post)
      std::vector<CAnimFrame *> AnimFrames;
      
      //pointer to MFC window that this animation belongs to
      CWnd *m_pWindow;
    
      //Size of animation (horiz and vert)
      DWORD m_dwSize;
    
      //Position of animation
      CPoint m_Position;
    
      //Current frame ID
      DWORD m_dwCurFrame;
    
      //Accumulated time for current frame
      float m_fAccumTime;
    
      //Pointer to tile manager
      CTileManager *m_pTileManager;
    
      //Looping animation flag
      bool m_bLooping;
    
      //DC of CWnd for this animation
      CDC       *m_pCDC;
    
      //Bitmap (not currently used)
      //CBitmap   *m_pBitmap;
    
      //Thread object for this animation
      CWinThread *m_pThread;
      
      //Client rect for window this animation resides in
      CRect m_rectClient;
    
      //Current scroll values of window this animation resides in
      int m_iScrollX;
      int m_iScrollY;
    
      //Update position flag - true =animation moves, false=animation 
      //is stationary and xoffset and yoffset are ignored
      bool m_bUpdatePos;
    
      //Current time
      float m_fCurTime;
    
      //Last time
      float m_fLastTime;
    
      //Active boolean for animation
      bool  m_bActive;
     
      public:
        CAnimSequence(void):m_dwCurFrame(0),m_Position(0,0),m_bLooping(false),
                            m_fAccumTime(0.0f),m_pTileManager(NULL),
                            m_pCDC(NULL),m_pBitmap(NULL),m_iScrollX(0),
                            m_iScrollY(0),m_bUpdatePos(false),m_pThread(NULL),
                            m_fCurTime(0.0f),m_fLastTime(0.0f),m_bActive(false) {}
    
        virtual ~CAnimSequence(void)
        {
          if (m_pCDC) 
          {
            m_pCDC->Detach();
            delete m_pCDC;
          }
          
          AnimFrames.clear();
          
        }
    
        //Return TileManager TileID of frame with ID of dwID
        DWORD GetID(DWORD dwID)
        {
          if (dwID<AnimFrames.size())
          {
            return AnimFrames[dwID]->m_dwTileID;
          } else return 0xFFFFFFFF;
        }
    
        //Set animation offsets
        void SetXYOffsets(DWORD dwID,float xo,float yo)
        {
          if (dwID<AnimFrames.size())
          {
            AnimFrames[dwID]->m_fXOffset=xo;
            AnimFrames[dwID]->m_fYOffset=yo;
          }
        }
    
        //Get animation offsets
        void GetXYOffsets(DWORD dwID,float &xo,float &yo)
        {
          if (dwID<AnimFrames.size())
          {
            xo=AnimFrames[dwID]->m_fXOffset;
            yo=AnimFrames[dwID]->m_fYOffset;
          }
    
        }
    
        //Set frame duration for frame with id of dwID
        void SetFrameDuration(DWORD dwID,float fDuration)
        {
          if (dwID<AnimFrames.size())
          {
            AnimFrames[dwID]->m_fFrameDuration=fDuration;
          }
        
        }
    
        //Get frame duration for frame dwID
        float GetFrameDuration(DWORD dwID)
        {
          if (dwID<AnimFrames.size())
          {
            return AnimFrames[dwID]->m_fFrameDuration;
          } else return (0.0f);
        }
    
        //Create animation and start thread
        void Create(CWnd *ptrWin,
                    CDC  *ptrCDC,
                    DWORD dwSize,
                    CPoint pos,
                    CTileManager *ptrTileManager,
                    bool bLooping=true,
                    bool bUpdatePos=false)
        {
          m_pWindow=ptrWin;
          m_dwSize=dwSize;
          m_pCDC=new CDC();
          m_pCDC->Attach(*ptrCDC);
    
          ptrWin->GetClientRect(&m_rectClient);
          m_iScrollX=0;
          m_iScrollY=0;
          m_bUpdatePos=bUpdatePos;
          m_Position.x=pos.x;
          m_Position.y=pos.y;
          m_dwCurFrame=0;
          m_pTileManager=ptrTileManager;
          m_bLooping=bLooping;
          m_fAccumTime=0.0f;
          m_fLastTime=(float)::timeGetTime();
          m_pThread=AfxBeginThread(DoThreading,this,THREAD_PRIORITY_IDLE);
    
          m_bActive=true;
        
        }
    
        //Add frame with Tile ID dwID, etc.
        void AddFrame(DWORD dwID,float fFrameDuration,float xo,float yo)
        {
          CAnimFrame *frame=new CAnimFrame();
          frame->Create(dwID,fFrameDuration,xo,yo);
          AnimFrames.push_back(frame);
        }
    
        //Another way to set important frame data, if needed
        void SetFrameData(DWORD dwID,float fFrameDuration,float xo,float yo)
        {
          if (dwID<AnimFrames.size())
          {
            AnimFrames[dwID]->m_fFrameDuration=fFrameDuration;
            AnimFrames[dwID]->m_fXOffset=xo;
            AnimFrames[dwID]->m_fYOffset=yo;
          }
        }
    
        //Set current frame to dwID if valid
        bool SetCurFrame(DWORD dwID)
        {
          if (dwID<AnimFrames.size())
          {
            m_dwCurFrame=dwID;
            return false;
          } else return true;
        }
    
        //Reset animation (loop it)
        void Reset(void) {m_dwCurFrame=0,m_fAccumTime=0.0f;}
    
        //Update function - timeDelta is time elapsed since last Update
        void Update(float fTimeDelta);
    
        //Draws current frame of animation
        void Draw(void);
    
        //DoThreading static member
        //Thread entry point
        static UINT DoThreading(LPVOID p)
        {
          CAnimSequence *ptrSeq=(CAnimSequence *)p;
          
          //While this animation is active
          while (ptrSeq->m_bActive)
          {
            //Get current time   
            ptrSeq->m_fCurTime=(float)::timeGetTime();
    
            //Subtract froim last time to get elapsed time
            float fElapsed=ptrSeq->m_fCurTime-ptrSeq->m_fLastTime;
          
            //Update frame based on timedelta
            ptrSeq->Update(fElapsed);
    
            //Set last time to current time
            ptrSeq->m_fLastTime=ptrSeq->m_fCurTime;
          }
          
          return (0);              
        }
       
        
    };
    CAnimSystem.cpp
    Code:
    #include <stdafx.h>
    #include "CAnimSystem.h"
    #include "MainFrm.h"
    
    //Update function for animation
    void CAnimSequence::Update(float fTimeDelta)
    {
      //Not used - DC was null here for some reason
      //m_pCDC=m_pWindow->GetDC();
    
      //If vector is not empty
      if (AnimFrames.size()>0)
      {
    
        //Add delta to accumulated time
        m_fAccumTime+=fTimeDelta;
    
        //Check to see if we need a frame change
        if (m_fAccumTime>=AnimFrames[m_dwCurFrame]->m_fFrameDuration)
        {
          //Yes we do so draw
          Draw();
          //Rest accum time
          m_fAccumTime=0.0f;
    
          //Advance animation forward by 1 frame
          m_dwCurFrame++;
    
          //Check for end of annimation sequence
          if (m_dwCurFrame>AnimFrames.size()-1)
          {
            //Loop animation (does not check loop bool yet)
            m_dwCurFrame=0;
            m_fAccumTime=0.0f;
         }
        }
      }
    
    }
    
    void CAnimSequence::Draw(void)
    {
      //Draw to pDC with TileDC
      //If vector is not empty
      if (AnimFrames.size()>0)
      {
        
          //Get Tile ID from vector
          DWORD dwTileID=AnimFrames[m_dwCurFrame]->m_dwTileID;
          //Get TileDC from tile manager
          CDC *TileDC=m_pTileManager->GetDC(dwTileID);
       
          //Setup x and y locations
          int ScreenX=m_Position.x+AnimFrames[m_dwCurFrame]->m_fXOffset;
          int ScreenY=m_Position.y+AnimFrames[m_dwCurFrame]->m_fYOffset;
        
          //Update position if specified
          if (m_bUpdatePos)
          {
            m_Position.x=ScreenX;
            m_Position.y=ScreenY;
          }
    
          //Move position relative to scroll values
          ScreenX+=m_iScrollX;
          ScreenY+=m_iScrollY;
        
         
          //If animation is visible, draw it
          if (ScreenX>m_rectClient.left  && 
              ScreenX<m_rectClient.right && 
              ScreenY>m_rectClient.top   &&
              ScreenY<m_rectClient.bottom)
          {
         
            if (m_pCDC!=NULL)
            {
              m_pCDC->BitBlt(ScreenX,ScreenY,
                             m_dwSize,
                             m_dwSize,
                             TileDC,
                             0,0,
                             SRCCOPY);
            }
    
               
              
              
    
          }
      
        
        
      }
    }
    Last edited by VirtualAce; 12-28-2005 at 05:27 PM.

  4. #4
    the Great ElastoManiac's Avatar
    Join Date
    Nov 2005
    Location
    Republika Srpska - Balkan
    Posts
    377
    use Sleep() in your loop!
    lu lu lu I've got some apples lu lu lu You've got some too lu lu lu Let's make some applesauce Take off our clothes and lu lu lu

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Recoding so each sleep pauses 1/10th of the total frame time.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. MFC Controls and Thread Safety :: MFC
    By kuphryn in forum Windows Programming
    Replies: 0
    Last Post: 12-06-2002, 11:36 AM
  2. WIndows programming?
    By hostensteffa in forum Windows Programming
    Replies: 7
    Last Post: 06-07-2002, 08:52 PM
  3. Release MFC Programs & Dynamic MFC DLL :: MFC
    By kuphryn in forum Windows Programming
    Replies: 2
    Last Post: 05-18-2002, 06:42 PM
  4. Beginning MFC (Prosise) Part III - Now What? :: C++
    By kuphryn in forum C++ Programming
    Replies: 5
    Last Post: 03-03-2002, 06:58 PM
  5. MFC is Challenging :: C++
    By kuphryn in forum C++ Programming
    Replies: 8
    Last Post: 02-05-2002, 01:33 AM