Re: Exiting a Do-While loop
The most straight-forward solution is to run your loop in a separate thread. Otherwise, as you already found out, your program will not "yield" any processor time to handling of other tasks in your program, like clicking on the "Quit" button.
Threads, however, intorduce complications into your program, most notably the need to synchronize access to shared data and to synchronize inter-thread event communications. One alternative to a separate thread is a so-called "gaming loop" for your message loop. For example, see http://www.codeproject.com/wtl/wtlgameloop.asp or http://www.mvps.org/directx/articles..._game_loop.htm
This transforms your message loop into a sort of poor-man's multi-threaded app, except that there's only one thread. To work successfully, however, you will need to ensure that your "continual loop" is actually broken up into iterations, and that only one iteration is run before yielding to the PeekMessage part of the message loop.
Incidentally, I won't tell you why your app is crashing (even though it's fairly evident) because your design is truly "not recommended". See, for example, the comments on PeekMessage in "The n Habits of Highly Defective Windows Applications" at http://www.flounder.com/badprogram.h...age%20anywhere
Mike
Re: Exiting a Do-While loop
Quote:
Originally Posted by mmscg
My project requires a continual loop.
The following code compiles and runs, but crashes with the error
The instruction at "0x00000064" refrenced memort at "0x00000064". The memory could not be "read".
when the Quit button is depressed.
Can anyone spot the problem?
The PeekMessage, DispatchMessage and TranslateMessage functions use MSG type not UINT as parameters. Try this :
Code:
do
{
MSG msg;
while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
{
DispatchMessage (&msg);
TranslateMessage (&msg);
}
}
while (bQuit == FALSE);
Re: Exiting a Do-While loop
amarcode:
Works great! Thank you! :D
MikeAThon:
I checked out PeekMessage on the ....badprogram... link :D
I could not understand anything the author was trying to say (except I am breaking every rule in the book)
because his code snippets all use MFC, which I know nothing about.
I also looked at the "game loop" links you provided, and they seem identical to what I am trying to do except
they wrap this "continual loop" around the WinMain message pump.
In my situation I only wanted to activate this loop at a press of a button (and exit it in the same way).
If I still am not understanding what you are trying to say, please respond.
And thanks also for again taking time to help!
Re: Exiting a Do-While loop
You may also want to check your CPU utilization when running this loop. You might want to put a Sleep in there to yield to other running processes (such as the operating system)...
Code:
do
{
MSG msg;
while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
{
DispatchMessage (&msg);
TranslateMessage (&msg);
Sleep(0);
}
}
while (bQuit == FALSE);
Hope this helps,
- Nigel
Re: Exiting a Do-While loop
Yes I have Sleep(0); in my loop.
I really wasn't sure where to put it so I ended up putting it here:
Code:
do
{
MSG msg;
while ( PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) )
{
DispatchMessage (&msg);
TranslateMessage (&msg);
}
Sleep(0);
}
while (bQuit == FALSE);
Do you think it makes a difference as to where in the loop?
Re: Exiting a Do-While loop
Ah, so you do... :p
If you have a lot of messages (depending on what you're doing), the inner loop could snag 100% of the CPU time while processing messages.
Putting the Sleep inside the inner while would avoid this, but given a regular set of messages, as you have it will likely be fine.
( I would have put it in the inner loop, but that's just me )
Regards,
- Nigel
Re: Exiting a Do-While loop
So to be safe, I shall move it then.
Thanks! :)
Re: Exiting a Do-While loop
Sleep(0) should not be used here. It causes the current thread to yield the remainder of its time-slice to any other thread in the system with a higher current priority. It therefore will do two things here which seem wrong: it will rob your own program of valuable CPU time that it probably needs to complete its own tasks, and it will mask problems caused by incorrect program architecture that improperly over-utilizes the CPU.
The thread scheduler in Windows is smarter than your program about when to stop your program (at the natural end of its timeslice) and to let others run in their timeslice. Let Windows do its job.
@mmscg: To use the "game loop", your "run" button should merely set a global boolean to TRUE, and your "quit" button should set it to false. Then, in the main message loop, test the value of the global and run your "contiual loop" if it's TRUE and don't if it's FALSE.
Mike
Re: Exiting a Do-While loop
Mike,
I disagree.
Removing the sleep prevents the windows task scheduler from doing its job, by forcing this thread to consume almost all of the spare CPU cycles in the machine.
By giving up the remainder of the timeslice, you are permitting window to perform other essential scheduling.
Otherwise in a tight loop, like this...
while(1)
;
This thread will use 100% of the CPU, regardless of its thread priority and other applications will not have their required share of the slices.
In fact I would go as far as saying that without the sleep in his loop, the thread will consume 100% of his CPU, while it is sitting doing (next to) nothing.
Hope this helps,
- Nigel
Re: Exiting a Do-While loop
I found this in a Microsoft article:
Quote:
DoEvents is a Visual Basic function that yields execution so the operating system can process other events. This function cleans out the message loop and executes any other pending business in the Visual Basic runtime. Upon completing the pending business execution, the function calls the Sleep function with zero (0) as the argument so that the remaining time slice can be used to check the queue.
The Sleep 32-bit API function is a subset of the DoEvents function. The Visual Basic program calling the function and the Visual Basic runtime executable and interactions with Windows are immediately put to sleep by this function. The programs remain inactive for the time in milliseconds specified in the Sleep argument.
The Sleep function allows you to specify the amount of time your applications are inactive. The DoEvents function returns control to the Visual Basic program after the operating system has finished processing the events in its queue and all keys in the SendKeys queue have been sent.
Does this say where they put the Sleep(0) call?
Re: Exiting a Do-While loop
Don't try to use VB concepts in Win32 programming, at least not without understanding the full VB framework. For example, if the text you quoted is referring to the Win32 Slepp() API function, then it makes no sense to say that "the Sleep function [is called] with zero (0) as the argument so that the remaining time slice can be used to check the queue." The Win32 Sleep function immediately yields the time-slice, so that there's nothing left with which to "check the queue". Tis makes me think that the quoted text is referring to some VB wrapper to the Sleep() function, that does some extra work with the VB framework before it calls the actual Win32 Sleep() function.
You need to describe what you want to do in your "continual loop". But again, I strongly recommend against Sleep(0), and you probably will not need it.
@Nigel: I know you disagree, but Sleep(0) is usually a sign of architecture that needs improvement. For example, the programmer does not know why the app is eating 100% CPU time and feels it should not be, but can't figure out any other way to stop it, so he sticks a Sleep(0) (or worse, a Sleep(100)) in it. This would be a bad reason to use Sleep().
One common use of Sleep(0) is in multi-threaded situations, where you need to play some sort of inter-thread "catch up" and you have determined that one thread has done all it can for now, and must wait for another thread to complete processing that the first thread needs. In such a situation, the first thread's continued use of its time-slice is wasteful, since we already know that it can't do anything further; it should therefore yield its time-slice, and Sleep(0) might make sense here. (WaitForSingleObject might make more sense, but each situation should be evaluated on its own.)
Mike
PS: There's almost never a justification for using Sleep(100), or anything above Sleep(0), for the reason that the "100" is usually an arbitrary number that the programmer found experimentally to "get it to work", without fully understanding why it didn't work in the first place. This is guaranteed to fail on someone else's system, at some time in the future.
1 Attachment(s)
Re: Exiting a Do-While loop
Quote:
You need to describe what you want to do in your "continual loop". But again, I strongly recommend against Sleep(0), and you probably will not need it.
I thought I would be able to complete this on my own... I was wrong.
I was continuing with the "double-buffering" for graphics. I could not get the previous one working, so I continued to read up on the subject, thought I understood it, implemented it in VB (works GREAT), and now trying to build it in C++ Win32.
The "continual loop" is there to generate random graphics in the "PictureBox", so that I could watch the effect with double-buffering ON and OFF (I didn't want to use a timer).
I am posting my code. It builds and runs, but NO graphics appears in my "PictureBox".
I tried calling UpdateFrame in the WM_PAINT handler, and InvalidateRect whereI had called UpdateFrame.
This didn't work, and in fact caused strange screen behaviour.
If anyone is able to help, it would be appreciated, as I am becoming very frustrated, that this graphics part is not really sinking-in for me.
Re: Exiting a Do-While loop
OK, I don't think the problem is a graphics one, but rather not understanding how to return an array thru a function
I have a user-defined type "Box" and I declare an array GraphicObject[20] of type Box
In my function UpdateFrame, I call the function MoveGraphicObject
inside a for-loop that should fill all the parameters of a 20 element array.
ie
Code:
for (i=0; i<=19; i++)
{
MoveGraphicObject(GraphicObject[i]);
}
Since GraphicObject is declared a global variable these values should be available anywhere in the program
In my MessageBox "debugger"
Code:
wsprintf (cBuf, "%d", GraphicObject[i].x1 );
MessageBox(NULL, cBuf, "Test", MB_OK);
always returns zero (ditto GraphicObject[i].y1, GraphicObject[i].x2,GraphicObject[i].y2, etc.)
yet I know MoveGraphicObject is calculating the values correctly because I do a similar test inside that function, and values other than zero are displayed.
Can anyone see, what I am doing incorrectly in this regard?
Re: Exiting a Do-While loop
I changed:
Code:
void UpdateFrame()
{
for (i=0; i<=19; i++)
{
MoveGraphicObject(GraphicObject[i]);
}
}
Box MoveGraphicObject(Box Obj)
{
if ( Obj.newB == TRUE )
{
Obj.newB = FALSE;
}
}
to:
Code:
void UpdateFrame()
{
for (i=0; i<=19; i++)
{
GraphicObject[i]=MoveGraphicObject(GraphicObject[i]);
}
}
Box MoveGraphicObject(Box Obj)
{
if ( Obj.newB == TRUE )
{
Obj.newB = FALSE;
}
return Obj;
}
Would this be the proper way?