MFC and threads.

Hello,

I'm making a visual interface for an algorithm. To get period visual updates, I want my algorithm to run in a separate thread from the visual stuff. I get a debug assertion error (wincore.cpp, line 934).

I tried to do it like this:
-The algorithm is defined in the Doc. It uses nothing MFC-ish or otherwise Windows-ish except for a call to Invalidate().
-The thread-controlling function looks like this (in the View):
1
2
3
4
5
6
UINT thAnimateOpt(LPVOID lp){
	TRACE("INSIDE ANIMATEOPT.\n");
	((CVisualDoc*)((CFrameWnd*)AfxGetApp()->GetMainWnd())->GetActiveDocument())->animate();
         TRACE("OUTSIDE ANIMATEOPT.\n");
	return 0;
}

-The command handler that starts the thread looks like this (in the View):
1
2
3
4
5
6
void CVisualView::OnAnimation()
{
	TRACE("STARTING THREAD.\n");
	CWinThread *optThread = AfxBeginThread(thAnimateOpt, GetSafeHwnd(),  THREAD_PRIORITY_NORMAL);
	TRACE("THREAD STARTED.\n");
}


According to the traces, the crash happens in the call to animate() inside the thread-controlling function.

Anyone have an idea why? Most of the code is copypasted from a previous visual interface that did work, so I'm rather confused.
If it is a debug assertion, what is it that is asserting?
It is very poor design to access GUI controls from worker threads.
Only main thread must be allowed to update GUI. Instead, post a custom message from worker thread to gui thread which updates the controls instead.
If you really need to do GUI work on an another thread, you can't just use a thread function. That form of AfxBeginThread is just for worker threads (i.e. no message pump). Instead, you need to derive a new class from CWinThread, so your new thread has its own message pump.

But as mordoran said, it's generally seen as poor design to do GUI stuff on a worker thread. Normally they do data crunching, i/o, etc. and leave the GUI work to the main thread.

Also, your animate() method is on the document. It should be on the view. In the document-view architecture, it's the view objects that handle the displaying. For example, you could have one view animating the document and another veiw showing the statistics of the same document.
Sorry for the delay, I've been gone for a few days.

My 'animate' method is in the document because it runs an algorithm and saves the result to "state" variables (members of the document). The View document draws based on these Document members, but has no members of its own.

The worker thread that runs animate() calls Invalidate() because I want to see some intermediate results. I do this by keeping two sets of state variables (current & previous) and updating them at regular intervals inside animate() [actually, to be precise: inside a function called by animate()].

How do you suggest I reorganize this?
Ah, ok. The name "animate" made me think of GUI stuff.

One possibility would be to define a custom message (WM_USER + your offset) and then add a handler to your view which calls Invalidate() when it's triggered.

You then provide your thread with the HWND to the view and use PostMessage with your custom message to trigger the redraw. All GUI work will then be done on the main thread.

Or you could use PostThreadMessage instead, which works with the thread id rather than the HWND.

Last edited on
Thanks, I'll look into that!
Topic archived. No new replies allowed.