Major Multithread Problem :: MFC

kuphryn

Senior member
Jan 7, 2001
400
0
0
Hi.

I just found a major multithread bug a program I working on. First, I will describe the process that is causes the major multithread problem.

-----
- user opens a text file (any size) w/ text only
- user clicks an option in the menu
- view has a executes its message handler for the menu item
- view calls a function in doc
- doc begins a new thread (thread includes CSinglelock + CriticalSection, data from doc)
- thread resumes and begins processing the data
- when done, thread *PostMessage* mainframe that is done ::: -> AfxGetMainWnd->PostMessage(WM_USER_THREAD, 0, 0);
- main frame *SendMessage* to view ::: -> pView->SendMessage(WM_USER_THREAD, 0, 0)
- view calls a function in doc to close thread
- doc class this function
-----
////
// This function is called to close a thread
//
m_bThread = true; // meaning thread is still active

if (m_pThread && m_hThread) // m_hThread is a HANDLE to the thread
{
::WaitForSingleObject(m_hThread, INFINITE);
delete m_pThread;
m_pThread = NULL;
m_hThread = NULL;
m_bThread = false; // meaning thread has been closed

SetModifiedFlag(TRUE);
}

UpdateAllViews(NULL);
-----

Okay. Everything works good *if the use does not click anything* during the process. In other words, if the user were to click the menu or anything inside the window, the program would malfunction.

Notice the bool "m_bThread." I use it as an indicator about the status of the thread. if m_bThread is true, meaning that the thread is active, the program disables many options in the menu. These options will remain disabled unless m_nThread is false. For some reason, that variable remains *true* if the user starts clicks anyone in the menu or view processing. That means something is keeping the program to ever setting m_Thread to false. On the other hand, if the user does not click anything until after the process is over, everything works as planned.

I have no idea what is going on in the background. Is there a design flaw anywhere?

Thanks,
Kuphryn
 

EagleKeeper

Discussion Club Moderator<br>Elite Member
Staff member
Oct 30, 2000
42,589
5
0
You state that the view calls a function in the doc.
Assumption is that the function creates the trhead and exits, returning control back to the view.

1) Does the thread terminate on its own after Posting a Message back to the MainFrameWindow

2) Have you trapped the MouseClick at the MainWindow to trace where they are being routed to.

Do not have the answers for you - trying to float up a baloon for you to look at and maybe trigger a positive response.
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Thanks.

Another member posted at GameDev about ::ExitThread. Infact, I never implemented ::ExitThread after the thread finishes (right before *PostMessage* to main). I did not know abut ::ExitThread. I do know about ::TerminalThread from Prosise's book. He recommended not using that Afx function.

As of right now I have no idea what is causing the program to not working correctly. The only thing I can think of is main is ignore the *PostMessage* from the worker thread if the user starts clicking away while the worker thread is going.

I will implement ::ExitThread as soon as I get home.

Kuphryn
 

EagleKeeper

Discussion Club Moderator<br>Elite Member
Staff member
Oct 30, 2000
42,589
5
0
Remember that Send Message hangs the issuing thread until the message is handled by the receiver. PostMessage is just a shoot it off and keep on rolling.
 

singh

Golden Member
Jul 5, 2001
1,449
0
0
How exactly does the "program malfunction"? Also, run Spy++ and watch all the messages being generated (especially when you click the mouse). That may give you some info incase the program is crashing. Might be an infinite message loop somewhere.
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Thanks.

The only time the worker thread *SendMessage* to main thread (UI) is to update the progress bar. Prosise's actually uses *SendMessage* in the image view program in his book. I wonder why he uses *SendMessage* for the progress bar and *PostMessage* after the worker thread closes.

I tried implementing *both* *PostMessage* and *SendMessage*. I ran into the exact same program.

Oh. What is Spy++? I am not familiar with that tool.

Okay. Here is a scenario where the program "malfunctions."

----
- user open text file // program copies data into a list of CString and displays data line by line
- user click option in menu to manipulate data
- view calls doc to begin a worker thread
- doc create a new worker thread via heap AfxBeginThread(...)
- doc sets a bool m_bThread to indicate there is a worker thread in progress
- worker thread *PostMessage* and/or *SendMessage* main to update a progress bar
- main frame updates the progress bar
- right before worker thread returns, it *PostMessage* main to indicating closure
- main redirects the message to view
- view class a function in doc to close thread // "close" maining deleting pointer to the thread and reset m_bThread to false
----

Okay. The design above works perfectly if the user does not click the menu and windows numerous times while the progress. Doc handles ON_COMMAND_UPDATE_UI for the menu. If m_bThread is true, meaning there is a worker thread in progress, five menu options are disabled (i.e save, saveas, open, new, etc.). Only if m_bThread is false will ON_COMMAND_UPDATE_UI enable those menu options.

I cannot see a clear cut problem with the design. The problem has to have something to do with maybe message overlow to the point where main thread (UI) ignores the *PostMessage* update from the worker thread right before it ends. If main does not process that message, the function that is suppose to delete the pointer to the worker thread and set m_bThread to false never gets called.

Maybe I should calls the function that does the above (belongs to doc) right from main instead of directing a message to view.

Kuphryn
 

EagleKeeper

Discussion Club Moderator<br>Elite Member
Staff member
Oct 30, 2000
42,589
5
0
Spy++ is a tools from M$ that comes with Visual Studio.

It allows you to observe every message that is being passed within the application. You have the ability to filter what type of messages you wish to see.

Great tool.
 

kuphryn

Senior member
Jan 7, 2001
400
0
0
Hi.

I believe I have figured out the problem. Here is a scenario. Let say you have a program with splitter window. There are two views and both are CEditView. Let say the top view calls a worker thread. While the worker thread is active, you focus the lower view and begin typing. What is the chance that the worker thread will never get deleted?

I just simulated the scenario above using a very simple program with a progress bar. If I focus on another window wile the progress bar is active, the program will not delete the progress bar, period.

I can email or upload the source code to that simple simulation anyone wants to see it.

Thanks,
Kuphryn
 

singh

Golden Member
Jul 5, 2001
1,449
0
0
There is a "feature" of MFC that allows the "active view" to handle a message. For example, if you had a menu handler (say for deleting an item in view) defined in BOTH views, which view would get the notification? The active view.

For Post/SendMessage, I always work with raw Windows handles (HWND), and use the Win32 API calls using ::postMessage() and ::SendMessage().