Single thread to multi-thread conversion problem
-
I'm in the process of adding a separate thread for a certain type of processing done in an app which deals with very large files (sometimes more than 1GB), and can take several minutes. The app has been an ongoing project for the last several years, should have been done as a multi-threaded app to begin with, but I'm coming in a bit too late to think about that :sigh: Anyway, with a ton of help from searching around the message board here (thanks!) I've spawned the processing off to a different messaging thread, which has two messages it can respond to UWM_START and UWM_STOP. While processing, it responds back to the main thread with UWM_UPDATE_PROGRESS and then UWM_DONE_PROCESSING when finished. For the most part this works well. UWM_START kicks off the long processing and it periodically has a message pump loop it does so that if UWM_STOP is sent it can respond to it. This part is working well, but I'm having a problem with code that is shared between this thread and the main thread. The part that is spawned off shares A LOT of code with the rest of the project, the shared code contains many message pumping loops (which are needed because of the fact it was done as single threaded to begin with). When I comment out thoes message pump loops (and leave the one in the processing thread), everything works great. However, if those message pump loops are in there, then I get a couple of weird errors. This doesn't really make sense though, since the documention of the message functions indicate it's done on a thread-by-thread basis, so I shouldn't be messing any of the messages up. ... and why would one pump be ok, and more cause problems? My question is, are these extra message pump loops causing me problems, or are they just helping uncover some larger flaw with all the shared code? BTW, the message pump loops are implemented as suggested in many places on the board:
MSG msg; while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) AfxGetThread()->PumpMessage();
----- In the land of the blind the one eyed man is king. -
I'm in the process of adding a separate thread for a certain type of processing done in an app which deals with very large files (sometimes more than 1GB), and can take several minutes. The app has been an ongoing project for the last several years, should have been done as a multi-threaded app to begin with, but I'm coming in a bit too late to think about that :sigh: Anyway, with a ton of help from searching around the message board here (thanks!) I've spawned the processing off to a different messaging thread, which has two messages it can respond to UWM_START and UWM_STOP. While processing, it responds back to the main thread with UWM_UPDATE_PROGRESS and then UWM_DONE_PROCESSING when finished. For the most part this works well. UWM_START kicks off the long processing and it periodically has a message pump loop it does so that if UWM_STOP is sent it can respond to it. This part is working well, but I'm having a problem with code that is shared between this thread and the main thread. The part that is spawned off shares A LOT of code with the rest of the project, the shared code contains many message pumping loops (which are needed because of the fact it was done as single threaded to begin with). When I comment out thoes message pump loops (and leave the one in the processing thread), everything works great. However, if those message pump loops are in there, then I get a couple of weird errors. This doesn't really make sense though, since the documention of the message functions indicate it's done on a thread-by-thread basis, so I shouldn't be messing any of the messages up. ... and why would one pump be ok, and more cause problems? My question is, are these extra message pump loops causing me problems, or are they just helping uncover some larger flaw with all the shared code? BTW, the message pump loops are implemented as suggested in many places on the board:
MSG msg; while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) AfxGetThread()->PumpMessage();
----- In the land of the blind the one eyed man is king.Does the new thread do any UI stuff? My preference with threads is to use worker threads, not UI threads and get the main app to do any UI on behalf of the worker thread. Why do you need these message pump loops at all. This sounds like stuff we used to do back in the Win16 days to do mock background processing. I'd be trying hard to get rid of them all. Far out - new formatting buttons.:rose: Neville Franks, Author of ED for Windows www.getsoft.com and coming soon: Surfulater www.surfulater.com
-
Does the new thread do any UI stuff? My preference with threads is to use worker threads, not UI threads and get the main app to do any UI on behalf of the worker thread. Why do you need these message pump loops at all. This sounds like stuff we used to do back in the Win16 days to do mock background processing. I'd be trying hard to get rid of them all. Far out - new formatting buttons.:rose: Neville Franks, Author of ED for Windows www.getsoft.com and coming soon: Surfulater www.surfulater.com
The thread is technically a UI thread (as it's derived from CWinThread), but this is simply to use messaging. This allowed much cleaner handling of cancel and update code than what I was trying before with a strictly worker thread, and use of messages is going to allow me to do a little more with this thread than I am now. The main thread handles everything in the UI. Neville Franks wrote: Why do you need these message pump loops at all. This sounds like stuff we used to do back in the Win16 days to do mock background processing. I'd be trying hard to get rid of them all. This technique is actually talked about and recommended in several articles here on CodeProject, but you're right - that's basically what it is doing, these message loops are there for tasks that should have been spawned off as background tasks long ago but never were. I tried simply removing the loops via #ifdefs, all my crashes stopped but I then had user responsiveness problems when doing the tasks that are still in the main thread. Although I'm going to push that these other tasks get dropped into separate threads, it won't happen anytime soon so I'm rather stuck with them for now. Perhaps there is some subset of the loops that I can remove, but until I can figure this out I'm not going to be too confident of this thread. I still can't really figure out why the loops are causing problems. From everything I've read they should be OK. ----- In the land of the blind, the one eyed man is king.
-
The thread is technically a UI thread (as it's derived from CWinThread), but this is simply to use messaging. This allowed much cleaner handling of cancel and update code than what I was trying before with a strictly worker thread, and use of messages is going to allow me to do a little more with this thread than I am now. The main thread handles everything in the UI. Neville Franks wrote: Why do you need these message pump loops at all. This sounds like stuff we used to do back in the Win16 days to do mock background processing. I'd be trying hard to get rid of them all. This technique is actually talked about and recommended in several articles here on CodeProject, but you're right - that's basically what it is doing, these message loops are there for tasks that should have been spawned off as background tasks long ago but never were. I tried simply removing the loops via #ifdefs, all my crashes stopped but I then had user responsiveness problems when doing the tasks that are still in the main thread. Although I'm going to push that these other tasks get dropped into separate threads, it won't happen anytime soon so I'm rather stuck with them for now. Perhaps there is some subset of the loops that I can remove, but until I can figure this out I'm not going to be too confident of this thread. I still can't really figure out why the loops are causing problems. From everything I've read they should be OK. ----- In the land of the blind, the one eyed man is king.
If the thread doesn't do UI I'd definitely use a worker thread. Then use PostMessage() to communicate with the main app thread. If you can add a flag param to the common code functions that do the message pump that says whether to pump or not you can set this to false for your thread. Alternatively use this:
/** Returns true if the current thread is the main application thread. */ BOOL InAppThread() { return ( AfxGetApp() eq AfxGetThread() ); }
and then:if ( InAppThread() ) do message pump ..
Also look at http://www.codeproject.com/threads/threadlibrary.asp[^] which is very nice and also simple. Threads are way better and cleaner for CPU intensive tasks than trying to do this in message pumps. Of course you have to consider sychronization and potential deadlock issues as well. Welcome to the world of multithreading.:-D Neville Franks, Author of ED for Windows www.getsoft.com and coming soon: Surfulater www.surfulater.com -
If the thread doesn't do UI I'd definitely use a worker thread. Then use PostMessage() to communicate with the main app thread. If you can add a flag param to the common code functions that do the message pump that says whether to pump or not you can set this to false for your thread. Alternatively use this:
/** Returns true if the current thread is the main application thread. */ BOOL InAppThread() { return ( AfxGetApp() eq AfxGetThread() ); }
and then:if ( InAppThread() ) do message pump ..
Also look at http://www.codeproject.com/threads/threadlibrary.asp[^] which is very nice and also simple. Threads are way better and cleaner for CPU intensive tasks than trying to do this in message pumps. Of course you have to consider sychronization and potential deadlock issues as well. Welcome to the world of multithreading.:-D Neville Franks, Author of ED for Windows www.getsoft.com and coming soon: Surfulater www.surfulater.comThat little code snippet will be perfect for getting around those message loops for now, but I'll be pushing for doing this all in threads, and the link you provided looks like it may be about perfect for that. Thanks! ----- In the land of the blind, the one eyed man is king.
-
That little code snippet will be perfect for getting around those message loops for now, but I'll be pushing for doing this all in threads, and the link you provided looks like it may be about perfect for that. Thanks! ----- In the land of the blind, the one eyed man is king.
I'm glad I was able to be of help. There is an article here at CP by Newcomer about Worker Threads which you should read. Make sure you don't use SendMessage from thread, instead always use PostMessage(). All to do with deadlocks. Neville Franks, Author of ED for Windows www.getsoft.com and coming soon: Surfulater www.surfulater.com