|
What are you trying to do?
Have you really thought about how you've designed the application and what the requirements are, especially the timing requirements?
You've created two worker threads that do some kind of simulation and you want to alert the UI thread in order to display the result of the simulation, I guess.
When it comes to secondary threads you should never use ::SendMessage() because you may deadlock your application if the main thread doesn't pump messages. Use ::PostMessage() instead. David has already advised you regarding this matter.
Now to what I believe is the real problem if I may read a little between the lines of your posts....
Worker threads are mostly used when you have some kind of computing to do that takes a lot of time when you don't want your user interface to freeze up. When the computation is done you alert the UI thread by posting a user defined message.
Since you believe that you choke the UI thread with messages, I guess the simulation is done rather fast and thus would not need a secondary thread. Either that or your UI thread doesn't process messages the way it's supposed to.
It sounds like your simulation takes a lot less time than displaying the results of it which means that you choke the UI thread; for every message it processes it will get more than one in the queue and it's all downhill from there. Putting calls to ::Sleep() does not in any way solve the problem, it simply disguises it.
From my point of view this issue is more about design than how big the message queue is, or can be.
To be able to give a more accurate suggestion you have to provide more information about what you're trying to do; what is a simulation, how long does it take to perform a simulation, what kind of data is displayed and so on.
But based on the information you've given so far I would suggest the following:
Create a queue of your own that holds simulation results, e.g. std::queue . Protect the queue with a critical section since it will be read from the UI thread and written to from the worker threads. Let the UI thread periodically poll the queue and display the results.
Now this may be a solution that doesn't really meet the requirements of your application, but since you haven't mentioned them this can serve as a starting point.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Hi Roger,
from an earlier thread[^] I understood the two background threads perform simulations over and over again, and report back to the UI on every little simulation, hence every few milliseconds.
To me it does not make much sense to update the screen that often, the human eye can't cope, and most of the thread switching and messaging is just wasting CPU cycles.
|
|
|
|
|
Hi Luc,
Luc Pattyn wrote: and report back to the UI on every little simulation, hence every few milliseconds.
Mmmm, that's what I figured.
Luc Pattyn wrote: To me it does not make much sense to update the screen that often, the human eye can't cope
I agree completely and that was also one of my points when I mentioned the timing requirements. However, I may have expressed that point rather subtle...
Luc Pattyn wrote: most of the thread switching and messaging is just wasting CPU cycles.
Indeed.
Or as one from Chicago I had the privilege to work with a couple of years ago so colourfully said it: "it's just burning MIPS".
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Roger,
First, I want to thank you for your response. My program is simulated a financial process many times. My plan is to have one worker thread for each cpu or core on the machine. The basic outline is that the worker Thread does a simulation, reports the results to the GUI thread and then repeats the process. Typically, the process needs to be repeated about 10,000 times. However, this number is under user control and might be as high as 1,000,000. Each simulation takes about 10ms seconds depending on the data. At the moment, the amount of data it is reporting is about 16 bytes. This might increase a bit.
I am thinking that you are right, and that I need to redesign the application. My current thinking is not to use the Window’s message queue but instead have the worker thread call a method in the user’s object. I am going to call this method, reportingMethod. Now, suppose that two threads call this method at the same time, then I am going to have a problem. Therefore, I need to protect myself from this situation. My plan is do the following:
<br />
GUIClass:: ReportingMethod ( struct Report rep )<br />
{<br />
CSingleLock singleLock( &m_CritSection );<br />
singleLock.Lock();<br />
<br />
copy the data<br />
increment counter<br />
if counter % 4 == 0<br />
repaint the window<br />
end if<br />
<br />
singleLock.Unlock();<br />
<br />
}<br />
In the above example, m_CritSection is of type CCriticalSection and a member of the class GUICLASS. Do you or anybody else see a problem with this approach? Do I have the locking code right?
Bob
|
|
|
|
|
BobInNJ wrote: Do you or anybody else see a problem with this approach?
Yes, with the repaint the window part. Depending on the way you plan to do this, this may causes problems because you can't access GUI objects from another thread than the one they were created in.
In fact, a much better approach is quite similar as what you did: keep your function as it is but remove the repaint the window part. Instead simply send a WM_PAINT message to your window that will force a redraw. In the OnPaint handler, you can then access the data you sent. Of course, there you also have to protect the access using critical sections.
If the repainting part is much slower than the run of the simulation, you can have another approach: don't send a WM_PAINT message in the ReportingMethod function but instead create a timer in your UI thread. Whenever your timer fires, you repaint your window.
|
|
|
|
|
I agree, but...
Cedric Moonen wrote: send a WM_PAINT message to your window that will force a redraw.
O-oh, Cédric...
You must never send or post a WM_PAINT message. It's not a "real" message.
It works the same way as the WM_TIMER message; it never enters the message queue of the application.
The WM_PAINT message gets generated by the system upon calls to e.g. UpdateWindow() . Before generating the WM_PAINT message the clipping region is computed and there's also the BeginPaint() /EndPaint() requests that are skipped if WM_PAINT would be sent instead or being generated.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Mmh, yes, I was not sure about this so thanks for correcting me (in fact I never really played directly with WM_PAINT messages).
Well, then I think a better approach would be to send a user defined message and in the handler of this message, call Invalidate() to force the redraw.
|
|
|
|
|
Cedric Moonen wrote: I think a better approach would be to send a user defined message and in the handler of this message, call Invalidate() to force the redraw.
Absolutely.
But, as Luc also made a point of, it's not necessary to update the UI faster than the user can cope with.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
IMO my timer-based GUI update suggestion did not get adopted because it got called "polling" at one point (mind you, not by me) and "polling is bad" as we all know. But I would rather do something every 100 msec all the time, than have it requested by some background threads as often as they can.
And obviously, one can start and stop the "polling" timer at a higher level (say when the background threads start/stop). So "smart polling" could avoid a lot of trouble and save many many CPU cycles.
|
|
|
|
|
Luc Pattyn wrote: IMO my timer-based GUI update suggestion did not get adopted because it got called "polling" at one point (mind you, not by me) and "polling is bad" as we all know. But I would rather do something every 100 msec all the time, than have it requested by some background threads as often as they can.
Agreed.
I suggested something similar in this post above[^] where I actually used the phrase "poll".
There's no point in updating the UI faster than the user has a remote chance of keeping up with. I would have the worker thread do more work before it "reports"; I mean if you hire a carpenter to do a job, you don't expect him to tell you "now I've picked up my screwdriver" and so on. You want to know when the job is done, or if he for some reason cannot do the job.
(Another one of my carpenter analogies.... )
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Cedric,
Thanks for the response. When I wrote, reapint the window, I meant by that was to generate a WM_PAINT message. Polling seems inefficient to me and some what backwards. However, I suspect that in many cases it is the way to go.
Bob
|
|
|
|
|
Okay, but I think you should think real hard about what a "simulation" is.
Again, this is based on the little information you've given, but I would consider the process of doing the 10,000 times repetitive thing a "simulation". When that work is done, in the worker thread, you alert the UI thread and display the results. During the computation you have some UI object, such as a progress bar, to inform the user that his "financial process" is being simulated.
Regarding your question about problems with your code snippet, I think Cédric made a good point, apart from the WM_PAINT stuff.
But while we're at it, I recommend you to not use the MFC versions of synchronisation objects like CCriticalSection, read more here[^].
And you would also benefit from reading this[^].
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Windows 2000/XP: There is a limit of 10,000 posted messages per message queue. This limit should be sufficiently large. If your application exceeds the limit, it should be redesigned to avoid consuming so many system resources. To adjust this limit, modify the following registry key.
MSDN - PostMessage
|
|
|
|
|
Thanks for the response. On my system, there is no registry key: USERPostMessageLimit. By any chance, do you know what the default value for the size of the queue. It really seems that their should be a call to find out how big it is, and how many messages are currently in it.
In any case, I have decided to use a different approach in returning results from my threads.
Bob
|
|
|
|
|
I once worked on a project where we used the message queue for sending results to the GUI thread.
We first tried to use an atomic counter to control how many results there was in the message queue (max 1000). And then throttled the worker threads when they were sending results faster than the GUI thread could handle. This also ensured that we wouldn't take all memory available when there was many results.
We ended up with creating a special container, where one could push and pop resuls atomicly. And instead used the message queue to signal that the container changed state from empty to containing messages. And container stopped the worker threads with an event mutex, when the message limit (1000) was reached, and this event-mutex was signalled when the GUI thread had got the message count below 500. We changed to this solution because it was kind of a misuse of the message queue to contain our results, eventhough it was an easy way to get a thread-safe queue.
Guess right solution is not use the message queue at all, but check another queue when the GUI thread is in idle-state. And an even faster solution would be to let the container to have its own memory ¨
manager, where it reuses the allocated results, instead of constantly releasing and allocating results when popping and pushing.
|
|
|
|
|
I want to display HTML links inside edit control.
Single control need to have few hyperlinks separated for which display text is different from target URL.
While right clicking on it, it need to launch default browser.
Thanks in Advance
|
|
|
|
|
Not quite sure where the question is here. It sounds like you're telling us about your day.
Assuming you're needing some help with this...
http://www.codeproject.com/KB/static/pphtmlstatic.aspx[^] should be of some help to you.
Iain.
Codeproject MVP for C++, I can't believe it's for my lounge posts...
|
|
|
|
|
Hi Thanks for quick help!!
I think the same can be done in edit control.
Will check it.
Thanks!!
|
|
|
|
|
sabapathy_80 wrote: I think the same can be done in edit control.
Not with a normal edit control. You'll need to use a rich edit control instead.
"Love people and use things, not love things and use people." - Unknown
"The brick walls are there for a reason...to stop the people who don't want it badly enough." - Randy Pausch
|
|
|
|
|
Hi, I can display a single link now by that article, but I am trying to display more than one "HTML" link in single control.
Is there any article on the same?
Thanks..
|
|
|
|
|
sabapathy_80 wrote: ...but I am trying to display more than one "HTML" link in single control.
Is there any article on the same?
See here.
"Love people and use things, not love things and use people." - Unknown
"The brick walls are there for a reason...to stop the people who don't want it badly enough." - Randy Pausch
|
|
|
|
|
Thanks.. I'll look in it..
|
|
|
|
|
Take a look at this[^], might be usefull.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
|
found florin visalescu's code on the screen color picker: http://www.codeproject.com/KB/GDI/screencolorpicker.aspx?msg=2871007#xx2871007xx
what code do i use to actually "show" the color that the pointer is over?
Thank you!
|
|
|
|