#include "toolkit.h"
#include "window.h"
#include <iostream>
using namespace std;
DWORD WINAPI run (LPVOID param){
int i = 0;
while (1)
{
std::cout<<"Thread # "<<(char*)param << " loop #: "<<i++<<"\n";
Sleep(1000);
}
return 0;
};
int main()
{
Window w;
w.setVisible(true);
DWORD flag;
char* msgs[] = { "1", "2" };
HANDLE t1 = CreateThread(0,0,run,msgs[0],0,&flag);
if(!t1)
cout << "can't make thread 1\n";
MSG msg;
int i=0;
while (GetMessage(&msg,w.getHandle(),0,0)>0)
{
std::cout<<"Message # "<<i++<<"\n";
DispatchMessage(&msg);
//WaitMessage();
}
return 0;
}
There are two threads created, one with main, and one with CreateThread. what happeneds is that GetMessage never blocks and runs busy loop. t1 gets to run only when main's time quantum gets out. And the cpu gets 100% busy. First when I call WaitMessage, the main threads properly blocks and waits until there are messages to process, in which case t1 runs. I also experimented to put message pump in another thread and to call it from CreateThread funcion, but result was the same (I actually have msg pump in member function of Window class). Why is that case? According to docs and all examples GetMessage should block while there are no messages to process. Why does it not happen?
🔒 Locked
GetMessage() does not block!
Advertisement
Original Post
Hi, I am recently playing around with little application framework (mostly for learning purposes), and am about to hide the message pump in a wrapper class. According to docs and tutorials on the net, global win32 function GetMessage() should block untill there are no messages. On my system it does not block! It just returnes like PeekMessage and consumes cpu. First when I insert WaitMessage() can I get my thread to block. What I am trying to do is have several threads running, with possibly several gui threads, and of course would like them to sitt and wait while there are no input messages avialable. Below is some test example, made just to experiment with GetMessage and blocking; "Window" class is just plain win32 stuff wrapper (with hwnd, hdc and & co wrapped in for convenience) so I have omitted it:
GetMessage() will block until there is a message in the queue. If you are seeing a large usage of CPU then it is coming from some other part of your program.
If GetMessage() isn't blocking, it's constantly receiving some message (or there are just a ton of messages in the queue). I would print them out and see what they are.
The 100% CPU usage is because your application never blocks, as you've observed (for whatever reason). Thus your code is executing through the duration of the time slice. Most applications usually block at some point, such as for file I/O or sleeping.
The 100% CPU usage is because your application never blocks, as you've observed (for whatever reason). Thus your code is executing through the duration of the time slice. Most applications usually block at some point, such as for file I/O or sleeping.
Quote:
Original post by fitfool
Maybe GetMessage() is failing, thus, never blocking?
If GetMessage() fails the return value is -1 and so the loop will break.
Quote:
Original post by Colin Jeanne
GetMessage() will block until there is a message in the queue. If you are seeing a large usage of CPU then it is coming from some other part of your program.
:-) .... yes ... if you read entire text, you will understand that I am aware of this, and this not working is exactly reason why I made my post.
Have you played around and tested if GetMessage really blocks?
There is no special reason, I don't send any messages nor do I create anything special; just plain vanilla win32 window and message loop;
Observer that I am listening on messages for a certain handle; not all windows messages (but neither that seems to make any difference). And if I use WaitMessage; then the window thread properly blocks until there are some messages; According to docs, waitmessage shell not return until there is some message for the window; exactly like docs says for getmessage too. Maybe one should pass some certain range to getmessage in order to block it?
or there is maybe some bug in getmessage or something?
Have you ever tested yourself if getmessage really blocks your windowing thread?
Your message loop is incomplete
Might want to throw in a IsDialogMessage in there as well. I'm not sure if the lack of a TranslateMessage would cause this though as I've never had a loop without it. Otherwise it's most definitely a message which is being sent over and over. Also you can not create the window and have the message pump in different threads in case you've tried that.
I would guess that this is the full loop you want
and you only need one pump per thread not per window. Alternatively you can use the msg.hwnd attribute to make your life a bit easier.
[Edited by - asp_ on August 31, 2008 9:04:12 AM]
while (GetMessage(&msg,w.getHandle(),0,0)>0) { std::cout<<"Message # "<<i++<<"\n"; TranslateMessage(&msg) DispatchMessage(&msg);}Might want to throw in a IsDialogMessage in there as well. I'm not sure if the lack of a TranslateMessage would cause this though as I've never had a loop without it. Otherwise it's most definitely a message which is being sent over and over. Also you can not create the window and have the message pump in different threads in case you've tried that.
I would guess that this is the full loop you want
while(GetMessage(&msg,0,0,0)>0) { std::cout<<"Message # "<<i++<<"\n"; if(!IsDialogMessage(w.getHandle(), &msg)) { TranslateMessage(&msg) DispatchMessage(&msg); }}and you only need one pump per thread not per window. Alternatively you can use the msg.hwnd attribute to make your life a bit easier.
[Edited by - asp_ on August 31, 2008 9:04:12 AM]
I don't think GetMessage() actually suspends your thread, it just doesn't return until there is a new message.
Compare MSDN phraseology:
Compare MSDN phraseology:
Quote:
GetMessage
The GetMessage function retrieves a message from the calling thread's message queue. The function dispatches incoming sent messages until a posted message is available for retrieval.
Quote:
WaitMessage
The WaitMessage function yields control to other threads when a thread has no other messages in its message queue. The WaitMessage function suspends the thread and does not return until a new message is placed in the thread's message queue.
Quote:
Original post by joe_bubamara
Have you played around and tested if GetMessage really blocks?
Yes. I've written many Windows programs and have never had a problem with GetMessage() not blocking and causing my program to consume 100% of the CPU.
Quote:
Observer that I am listening on messages for a certain handle; not all windows messages (but neither that seems to make any difference). And if I use WaitMessage; then the window thread properly blocks until there are some messages; According to docs, waitmessage shell not return until there is some message for the window; exactly like docs says for getmessage too. Maybe one should pass some certain range to getmessage in order to block it?
Your message pump is a standard message pump. Nothing extra is needed.
Quote:
or there is maybe some bug in getmessage or something?
If such a bug existed it would be noticed almost immediately during the development of Windows. Further, it wouldnt just affect your window but all windows.
To find where the real issue lies, try this: remove parts of your program. Make the program as small as possible while still demonstrating the issue. Try removing the extra thread, try removing the window-wrapper class or simplifying its window procedure, etc. When you get to the point where removing anything else removes the problem you've probably found where the issue lies.
Quote:
Original post by _asp
Might want to throw in a IsDialogMessage in there as well. I'm not sure if the lack of a TranslateMessage would cause this though as I've never had a loop without it. Otherwise it's most definitely a message which is being sent over and over. Also you can not create the window and have the message pump in different threads in case you've tried that.
IsDialogMessage() is for handling messages for dialog boxes, such as common keyboard accelerators. It's not necessary. Similarly, TranslateMessage() is for converting WM_KEYDOWN and friends to higher-level messages like WM_CHAR. It's also not necessary if you dont need that functionality.
Quote:
Original post by dmatter
I don't think GetMessage() actually suspends your thread, it just doesn't return until there is a new message.
if "just doesn't return until something ..." should not be taken as blocking the thread until something happened then I don't know what should :-). But you are a bit right that I missunderstand the docs (wonder if I am the only one).
I have been looking at messages; and found that problem is one and same message; one numbered as 15, probably more familiar as WM_PAINT. Why this message is constantly posted to the qeue I have no idea. But it turned out, that it depends of my handling of paint msg:
when done like this:
LRESULT CALLBACK wndproc(HWND hwnd, switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; case WM_PAINT: break; } return DefWindowProc(hwnd,uMsg,wParam,lParam);then it seems to work properly and thread blocks. But if I instead of "break" use "return 0" in paint case; then system constantly posts wm_paint message to the qeue? Probably some more docs reading issues (I understood I should return zero if I handle this message :-): http://msdn.microsoft.com/en-us/library/ms534901(VS.85).aspx)I am posting a test app at the end of this post, so you can try it yourself (it will be ugly window, since all painting code is removed).
@jeanne - yes I DO know that message loop is per thread; and yes I do want to have every window run in it's own thread! This because those windows will be used as high-level containers for components that will use os window to render itself. Think Java's Swing if it is familiar to you.
Quote:Yes. You are right about that; and problem was with that return statement in WM_PAINT. If this is my (miss)understanding of docs, I don't know; but I certainly didn't expect it should re-post paint event over and over again if default winproc is not called.
If such a bug existed it would be noticed almost immediately during the development of Windows. Further, it wouldnt just affect your window but all windows.
Quote:
Try removing the extra thread
And how do you plan to see if another thread is getting to execute and when, while the main thread is blocked???? It can be difficult if you have only one thread in your app ;-).
App below is a simple one I made for this post for illustration, but same thing occur in my library where I have an opengl window doing it's own gl painting so this is probably issue with how system handles window procedure and messages. I don't know if this issue is well-known to others, but it wasn't to me; and if you WANT your window and thread to BLOCK, then be sure not to "return 0" in wm_paint, but to call default proc after your own paints. Remaining question is what happends to all those mystical wm_paint messages when we use WaitMessage; in that case they seem to be ignored.
#include <iostream>#include <windows.h>HWND hwnd;int width = 640, height = 480;DWORD WINAPI run (LPVOID param){ int i = 0; while (1) { std::cout<<"Thread loop #: "<<i++<<"\n"; Sleep(1000); } return 0;};LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; case WM_PAINT: //return 0; // this will post paint for ever ... to whom? break; } return DefWindowProc(hwnd,uMsg,wParam,lParam);// finally let windows do it's thing }bool createWindow(){ RECT WindowRect; WindowRect.top=(long)0; WindowRect.left=(long)0; WindowRect.right=(long)width; WindowRect.bottom=(long)height; WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = wndproc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(0); wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = L"win"; if(!RegisterClass(&wc)) return false; if (!(hwnd=CreateWindowEx(0,L"win",L"Window",WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, 0, 0, wc.hInstance, 0))) return false; return true;}int main(){ if(!createWindow()){ std::cout<<" no window \n"; return 0; } HANDLE t = CreateThread(0,0,run,(LPVOID)0,0,(LPDWORD)0); ShowWindow(hwnd,true); MSG msg; int i=0; while (GetMessage(&msg,0,0,0)>0) { std::cout<<"Message # "<<i++<<msg.message<<" \n"; DispatchMessage(&msg); //WaitMessage(); } return 0;}
Quote:
Original post by SiCrane
Did you try using ValidateRect() in your WM_PAINT handler to remove the requested area from the update region?
Actually I didn't. Now when you are syaing that I remeber that I probably should do that :-). Will try it asap ... thnks.
_______________________________________________________
Yes it does works, and it has to be "client rectangle";
case WM_PAINT: RECT rect; GetClientRect(hwnd,▭); ValidateRect(hwnd,▭); return 0; // this will post paint for ever ... to whom?thnks - I guess this answers & solves my problem :-).
Quote:
Original post by SiCrane
IIRC, if you don't properly process some messages they may not be removed from the queue. I believe WM_PAINT is one of these. Check to make sure that the return values from your message handlers properly match the proper success codes for the messages.
typical ... why did I miss that post??? .... could have saved me some time :-)
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement