Solved

UpdateAllViews crash Problem

Posted on 2008-06-23
4
659 Views
Last Modified: 2013-11-20
extern CMainApp theApp;

UINT __cdecl MyThread( LPVOID pParam );



the thread is started with AfxBeginThread(......)





in the thread functions


UINT __cdecl MyThread( LPVOID pParam )
{


 while(done == FALSE)
 {
        result = WaitForMultipleObjects(numHandles, pWaitHandles, FALSE,
           THREAD_WAIT_TIMEOUT);        //used to be INFINITE
 
       handleIndex = result - WAIT_OBJECT_0;

      switch(handleIndex)
        {
            case 0:
            //Happens every 1 second
                bResult = theApp.PostThreadMessage(WM_UPDATE_VIEWSETA, 0, 0);
                break;
            case 1:
            //Happens every 2 Seconds
                bResult = theApp.PostThreadMessage(WM_UPDATE_VIEWSETB, 0, 0);
            break;
            //Happens every 10 milliSeconds
            case 2:
                bResult = theApp.PostThreadMessage(WM_UPDATE_VIEWSETC, 0, 0);
                break;
              :
            :
      }
}


On recieving each of these messages UpdateAllViews is called with different hints hence OnUpdate for all views are called and will update if matching hint is recieved.
I am not passing any window handles across threads.


ViewA1::OnUpdate()
{
}
ViewA2::OnUpdate()
{
}
ViewA3::OnUpdate()
{
}


ViewB1::OnUpdate()
{
}
ViewB2::OnUpdate()
{
}
ViewB3::OnUpdate()
{
}


ViewC1::OnUpdate()
{
}
ViewC2::OnUpdate()
{
}
ViewC3::OnUpdate()
{
}






My Problem is

When the messages WM_UPDATE_VIEWSETA,WM_UPDATE_VIEWSETB and WM_UPDATE_VIEWSETC are being at 1,2 secs and 10 milisecs respectively, all views update fine.  
Now if I close a open View say ViewB1, then the program crashes.

Looking at the call stack, it crashes at

BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
      ENSURE(this != NULL);
      // it better be in valid memory, at least for CObject size
->>      ASSERT(AfxIsValidAddress(this, sizeof(CObject)));

      // simple SI case
      CRuntimeClass* pClassThis = GetRuntimeClass();

      ENSURE(pClassThis);
      return pClassThis->IsDerivedFrom(pClass);
}

This is being called by

CView* CDocument::GetNextView(POSITION& rPosition) const
{
      ASSERT(rPosition != BEFORE_START_POSITION);
            // use CDocument::GetFirstViewPosition instead !
      if (rPosition == NULL)
            return NULL;    // nothing left
      CView* pView = (CView*)m_viewList.GetNext(rPosition);
-->      ASSERT_KINDOF(CView, pView);
      return pView;
}


And the view is the ViewB1...Which has already been closed.

I checked step executing at the destructor , the CDocument::RemoveView() is being called for the view being removed.

Closing the view interrupts UpdateAllViews at the middle of its calls, nulls the window pointers for that view. When execution resumes back it UpdateAllViews application crashes. Wierd that MFC is supposed to synchronize this operation.

How can this happen?

Thanks



0
Comment
Question by:ghimireniraj
  • 2
  • 2
4 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 21853909
The posted messages are probably piled up in the queue, and one of the OnUpdate() calls is being executed during a moment in which the CView-derived object still exists, but the window it encapsulates does not.

In your WM_UPDATE_VIEWSETA handler, I suggest you verify that that all of the objects that are in your "viewset A" are still valid (and not in the process of being shut down).

BTW, a view update can take a looooong time (I'm thinking of one I wrote that involved database access).   In that case your worker thread will be thowing lots of update requests into the event queue, and they will just pile up and your program might never catch up.
0
 
LVL 3

Author Comment

by:ghimireniraj
ID: 21886323
Thanks Dan for your suggestions. Sorry I was out for few days and could not respond immediately.

>>>The posted messages are probably piled up in the queue, and one of the OnUpdate() calls is being executed during a moment in which the CView-derived object still exists, but the window it encapsulates does not.

How would I prevent this?


>>>>In your WM_UPDATE_VIEWSETA handler, I suggest you verify that that all of the objects that are in your "viewset A" are still valid (and not in the process of being shut down).

I wrote my own version of UpdateAllViews and I iterate through all view and check if the handles are null, (it could be bad pointers instead of nulls too) but this does not solve the problem since the window could even be destroyed right after it passes the invalid handle check, and before it makes the actual update call. SO I would think checking for valid window object didnot solve the problem although I see enough evidence that the crash happens due to bad handle to the window object.

>>>>>BTW, a view update can take a looooong time (I'm thinking of one I wrote that involved database access).   In that case your worker thread will be throwing lots of update requests into the event queue, and they will just pile up and your program might never catch up.

How would I prevent this?

Synchronizing the destroy and Update would not help either coz that would cause a deadlock.

It has been a hard problem to get around.

Any more ideas?









0
 
LVL 49

Accepted Solution

by:
DanRollins earned 500 total points
ID: 21886610
Without knowing the exact cause of the problem, I can describe a solution I found to a (possibly) similar problem I faced in a multi-threaded app.

Rather than do the update in the OnUpdate call, all I did was set an m_fNeedsUpdate flag in each View.  Then in the FrameWindow, I created a timer to and it would periodically check the flag of each active view and do the actual update during that timer cycle.

There are two advantages:  
1) Multiple update requests now collapse down to a single update action; this eliminates the chance that your program will do two time-consuming operations (such as db access, window redraw, etc.) when there is no need.

2) All of the update action runs on the main U/I thread.  MFC gets into strange error conditions when a worker thread does anything whatsoever with the U/I.  I understand that your PostThreadMessage() logic should avoid that, but the timer technique insulates the workers so completely that I never had a similar problem again.
0
 
LVL 3

Author Closing Comment

by:ghimireniraj
ID: 31469930
Thanks a Lot Dan...
0

Featured Post

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
conditional code and condition difference 9 84
pre4 challenge 19 104
withoutTen challenge 14 132
Execute multiple curl cmds with sleep and send output to file 10 104
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question