Regards,
hutch at movsd dot com
Isn't this post a perfect example of *YOU* changing the argument
around since you've been proven wrong, wrong and even more wrong
in all the other threads?
Go "poll some interrupts", and I'll continue to write efficient,
correct, well-synchronized code that works across all windows
versions without nasty side effects :)
No. What this really boils down to is that Hutch likes to get real long
threads going around here. Rene effectively ignored him most of the
time, now he's discovered the Iczelion and polling get things going, so
he's jumping all over those.
What was that word I was thinking of? Started with a "t" or something
like that :-)
Cheers,
Randy Hyde
==================================
Isn't this post a perfect example of *YOU* changing the argument
around since you've been proven wrong, wrong and even more wrong
in all the other threads?
==================================
This from the man who does not even understand the working of a Von
Neuman architecture computer but who found a few clunky Wait APIs a few
years ago and wants to wax lyrical about it.
Here is a man who uses system polling loops by way of his Wait states
and does not know the difference.
==================================
Go "poll some interrupts", and I'll continue to write efficient,
correct, well-synchronized code that works across all windows
versions without nasty side effects :)
==================================
Yeah, that 0.005% overhead per thread is a really nasty side effect.
How many percentage points did you say you could improve on 0.005% or
less ?
Show us all how to write a message loop and WndProc with your
efficient, correct, well-synchronized code that works across all
windows versions without nasty side effects by using your much flaunted
wait states alone.
Pssssssst, Sleep() is a system defined Wait state API.
Now here is a new one for the books, Randall Hyde in bed with the higly
self acclaimed leading guru of ALA, Betov himself.
==================================
No. What this really boils down to is that Hutch likes to get real long
threads going around here. Rene effectively ignored him most of the
time, now he's discovered the Iczelion and polling get things going, so
he's jumping all over those.
==================================
I wonder what we can expect next, SpasmLA, HLrotAsm or the
architectural genius of Randall Hyde coupled with the coding genius of
Betov to set new heights in Windows software. Such a marrying of minds
would have to be beneficial to all involved. Think of the sheer brutal
precision of Betov's data structures in the new HLA introduced under
the new and revised BLS (Betov Lcencing System).
==================================
What was that word I was thinking of? Started with a "t" or something
like that :-)
==================================
Yet another Freudian slip, Troll rhymes with Poll, You are almost there
as long as you Sleep() regularly. :)
Rgards,
> I wonder what we can expect next, SpasmLA, HLrotAsm or the
> architectural genius of Randall Hyde coupled with the coding genius of
> Betov to set new heights in Windows software. Such a marrying of minds
> would have to be beneficial to all involved. Think of the sheer brutal
> precision of Betov's data structures in the new HLA introduced under
> the new and revised BLS (Betov Lcencing System)
The only true thing, in this paragraph, is that
i _am_ a genius... and, believe, me it's a hard
job. I should have been a home marker, instead.
;)
Betov.
You have two prospective recruits here, Randall Hyde to give you
project some academic respectability and f0dder who is at a bit of a
loose end and is in need of guidance. As a reciprocal arrangement
Randall Hyde could teach you how to write PDF help files while f0dder
could tutor you in the art of treachery.
He could also handle all of the consultations with the "colonel" so you
could spend your time more profitably in the pursuit of the fame and
glory you so desperately need. Think of it, fame without end riding on
the back of of Randall Hyde while actually making f0dder useful at
last. Just as an aside, f0dder to teach you the art of MFC manipulation
inbetween slopping around C++ templates.
This is a once in a lifetime opportunity, whatever you do don't miss it
as its your ticket to the fame and glory you so desperately need.
A pleasure to help you out as usual. :)
> As a reciprocal arrangement
> Randall Hyde could teach you how to write PDF help files while f0dder
> could tutor you in the art of treachery.
The sad thing would be that, with friends like these,
i would no more need any ennemy like you, my dear good
old Dictionary-Ass.
:)
Betov.
Think of how nice all of your documentation would look in PDF format
and with a big name like Randall Hyde writing it for you, someone may
actually read it. f0dder could act as your front man for the script
kiddie generation and as he is the head honcho in the old
win32asm(VIRUS) channel he would have the contacts to help you improve
your distribution.
Regards,
And, as i feel a bit old and tired, maybe, as you can't
refrain from being an "Assembler-Written-By-Someone-Else
Maintainer", you could postulate, for becoming the next
RosAsm Main Maintainer, what would introduce the marvelous
capacity of importing junky Libs into RosAsm produced Code,
and of outputing childish Asm Routines, for you to include
in your Power-Basic thingies.
:))
Betov.
I found this one;
SpinAndPollInterrupts(void)
Unfortunately, when I called it, it never returned, and my machine
locked up. I think it's the parameter. The doc says to use the
parameter void. That sounds bad to me, as the void sounds like
somewhere you can't get out of. Can you help me debug this?
Oh, and I didn't use a semi-colon at the end of the statement, my
keyboard doesn't have one. Compiled OK though.
Thanks.
--
Regards
Alex McDonald
You will solve the problem with,
SetIdlePrioritySoLowItDoesNotMatter()
I gather you will have to ask for technical assistance from "Parsley"
for the semicolon syntax, if I put one at the end of a line, its to add
comments after it.
Now here is a question for you, with the two procedures,
SpinAndPollInterrupts(void)
WaitForf0dderDotLibNoTimeout()
Which one do you think will return first, I cannot distinguish between
the two in terms of success rate.
With professional looking PDF documentation written by someone with a
big name, you would start to hit the big time at last and at the other
end, with a bad mannered script kiddie in training you could at last
appeal to the other end of programming, particularly as so many of
these kids are good at MIRC scripting so they would feel at home with
your ANSI escape sequence notation.
You don't want to sink into the obscurity of a clapped out newsgroup
like ALA when you could aim for far wider horizons and become the
leading assembler guru you so desperately want to be.
Always a pleasure to point you in the right direction. :)
See point 7
Donkey
Hutch's guide to debating a programming question...
1. Make some outlandish claim
2. When challenged attempt to change the subject
3. If that isn't possible then insult the opponent
4. Invent some "facts" about why it must be done his way
5. When challenged to provide proof of those "facts", ignore it
6. Attempt to change the subject again
7. Start a new thread (return to item 1)
I am pleased that you see the method as so effective.
1. Write something trivial that works well.
2. Listen to years of invective and bullsh*t about why its wrong.
3. Deliver the proof that it works well.
4. Loop back to 2 on repetition.
5. Develop a "Who gives a PHUK" attitude to the invective and bullsh*t.
6. Loop back to 2 on repetition.
7. Dump the trash in ALA due to 5.
8. Loop back to 2 on repetition.
9. Share the nuisance value aroung in ALA.
10. Loop back to 2 on repetition.
11. Start testing the source of invective and bullsh*t over some years.
12. Loop back to 2 on repetition.
13. Spare the decent assembler venues from the invective and bullsh*t.
14. Loop back to 2 on repetition.
If all else fails, WaitForf0dderDotLibNoTimeout().
Steve,
As far as I am concerned the point has never been whether it works or
not, though your Shell function definitely does not work under all
possible circumstances. The point of this whole long argument is "is
this the right way to achieve this goal". I for one, and most others
here do not believe it is, it is sloppy and a hack and though it may
work to your satisfaction, it may not do so in the future. And before
you say that Microsoft would not make such fundamental changes to the
way Windows works, just look at XPSP2, with PAE mode making around 20%
of my commercially acquired apps useless until I disabled it. A good
example is Connectix Virtual PC, which cost me a fair bit of coin and is
incompatible with PAE mode (though it works fine once PAE is disabled).
Granted, PAE mode and it's consequences have little to do with the
subject at hand but it does demonstrate what happens when you stray too
far from Microsoft's recommended way of doing things. The moral of the
story is simply that Microsoft feels no compunction in breaking software
that does not comply with their specifications in future versions of the
OS and it is simply conform or die in a BSOD.
At some point you should consider what has been offered as valid
criticism and fix the function, I would think any good programmer would
welcome advice that would improve his code and make it more stable
across all versions of Windows. Perhaps not everyone has offered it in
this manner but many have and they (ie Randall Hyde) should not be
attacked for pointing out deficiencies and possible solutions to
something they believe to be a problem in the MASM32 library. Randall
has, as far as I know, never maliciously attacked you or attempted to
deride you in public but you seem to see fit to do so to him, attacking
his argument is fine but you are attacking him personally and that I
find both unnecessary and unwarranted. Attack me if you choose, I have
no reputation to uphold and have little regard for such things anyway.
The more I read you recent posts, the more I see the road that perhaps
Betov took to get where he is. Defend a small peice of code against the
swell of opinion just as a matter of principle, then stubbornly refuse
to change it even when it is demonstrably flawed. At some point the
argument becomes personal and vindictive then you find yourself on the
slippery slope to "Outer Betovia", the land of the ignored and
ridiculed. One simple way out is ofcourse to end the argument with the
old standby "Let's agree to disagree", one of my favourites by the way.
Donkey
I imagine that you well undersand that I sit up at night wringing my
hands and losing sleep over the opinions passed around in ALA. I have
always reduced technical matters down to testing and here the advice is
not worth listening to. I did in fact produce the 1000 thread demo of a
"shell" procedure for exactly this purpose as it very clearly
demonstrated that fashion does not beat function.
With the choice of flexible low level design that has been round since
computers started and some clunky high level routine of limited
application, I go for flexibility and efficiency every time and the
testing well proves the virtue of doing so.
Now when the major proponent colapses into preferring a HLT instruction
to the fundamental polling nauture of te entire OS and the underlying
hardware, the sum total weight of the criticism that has been flogged
for years comes into perspective, someone who wants to win an argument
at any cost when all they needed to do was learn to write reliable
software in the first place.
Now as far as functionality changes over time, I have only been writng
Windows software for 15 years straight and you can trust me on this
much, they have been breaking documented functionality with every OS
version they have ever released so there is nothing new here.
As you among others chose to atack my work on a design level, you
inherit the context that it occurs in and get the response tha the rest
get becase I have a different peer group that don't suffer the
blinkered approach to any particular programming tecnique and design
code on the basis of what it has to do, not what fashion it as to
conform to.
Now the swell of opinion in ALA over polling loop design has about the
same importance level to me as the swell of opinion about the moral
implicaions of using SPASM instead of anything else, somewhere less
than ZERO.
No-one is seriously interested in trying to replace the fundamental
polling nature of the entire Windows operating system with clunky high
level Wait state APIs because they are just not capable of doing so.
When your whole messaging system depends on a fundamental polling
design and this includes the guts or every running GUI application,
like it or not, your code runs as part of a polling loop so the point
being flogged is at best mute.
Its not as if reasonably current versions of Windows are hard to work
out if you have a tool like Proces Explorer. System idle process
followed by system interrupts, loaded processes and the rest is user
capcity.
Start and quit various applicaions and you an see the changes as they
occur and this is how you test the theories that have been expounded
here. Task Manager will tell you other things like te handle usage
count and the like and none of tis stuff is hard to use.
Come back to the fundamentals of what was the target of so many years
of abuse. A "shell" procedure is in fact a very old design that has
nothing to do with multiple synchronous applications and event timing.
It is basically stopping one application so you can run another and
when the external app has terminated, control returns back to the
calling app.
This is not the mechanics of a cluster of web servers or synchronising
the termination of a number of conditions so they all line up or any
other complex cosideration, it is still a very simple task and what I
have repeatedly rjected is te notion of "function creep". In a current
multitasking OS there is still the use of a "shell" procedure and all
you need do is understand the conditions that it must run under.
I could happily live with 1% prcesor usage for something so simple but
under test the percentage is about one 200th of one percent or less so
its fair to say that the fundamental code design is more than efficient
for the task.
I am sure you are aware that the Sleep() API is one of the Wait state
APIs that calls through two layers to the int 2Eh services in
NTOSKRNL.EXE. It correctly yields unused processor time bck to the OS
and is very easily adjusted by simply changing the millisecond delay
that it uses.
The difference is it is far more flexible that some clunky high level
wait state and you can easily adjust the loop design, add extra tests
to it, change the duration of the test depending on if the app has
focus or not and more or less anything you like.
That is why its superior technology, its put the control of the task in
the programmers hands, not endless ratting through broken or out of
date reference material trying to get some clunky high level junk to
perform a task that it may not be well suited for.
I have always been of the "Let's agree to disagree" disposition but if
someone chooses to disagree with me for years on end flaunting their
ill informed criticisms at the maximum of noise and invective, I can be
more than disagreeable in reply and in this contex you have no leverage
to prop up one of your newfound buddies in ALA.
I am sorry you have been foolish enough to take this position as I have
never had anything against you but your injury here is self inflicted.
I have had no injury inflicted here, you might imagine that you have
done some but it only counts if I am concerned about that kind of thing.
However I do believe that I am correct about the right way to code the
shell function and my library code passes every test that I could throw
at it without the thousands of context switches per second your suffers
or the 259 bug. So in the end, I feel no overwhelming urge to agree with
you on this one, but I see no point in arguing about it ad infinitum,
lending creedance to your opinion as if it were worthy of debate might
mislead some programmers.
Donkey
Its a case of picking the tree out of your own eye before you try and
invent a splinter in mine. If you know so little about testing, at
least don't burden me with your mistakes but do feel free to create the
non-polling version of a message loop and a WndProc with precanned high
level wait state API function calls.
As has already been mentioned a multitude of times, the version in
Donkey's library doesn't have any of these flaws. Considering that
you whine when people don't use the very latest up-to-the-minute service
pack of masm32, you should shut your trap :)
> Its a case of picking the tree out of your own eye before you try and
> invent a splinter in mine. If you know so little about testing, at
> least don't burden me with your mistakes but do feel free to create
> the non-polling version of a message loop and a WndProc with
> precanned high level wait state API function calls.
Guess what? GetMessage is a blocking API. B-l-o-c-k-i-n-g, spelled out
for you. This means not polling for a message, but being woken up once
a message is ready.
Like it or lump it a message loop is a polling loop and a WndProc is
part of a bigger polling loop run by the OS. Polling tecnology is
superior technology and proven at an operating system level by the
internal structure of the Windows messaging system. Without it no GUI
app would run.
Noting that Donkey posted the version that was supposed to be the
"correct" way to call a wait state, my criticism is perfectly valid and
he should fix it. Noting that you are defending his badly written
broken function, I guess you ae as ignorant of the right way to call a
wait state as he was when he wrote that function.
Make sure you shut a timer next time you copy a piece of my posted code
and try and apply it. Just another sloppy programming technique from
someone who does not know any better.
"Not return != blocking" - that's a true statement. GetMessage *could*
be polling. But it doesn't - it blocks. As for "internet technology",
well, sorry - your ignorance shows once again.
> Noting that Donkey posted the version that was supposed to be the
> "correct" way to call a wait state, my criticism is perfectly valid
> and he should fix it. Noting that you are defending his badly written
> broken function, I guess you ae as ignorant of the right way to call a
> wait state as he was when he wrote that function.
I'm not defending the snippet he posted here, I'm defending the code
in his library. You told him to go fix his library, but you obviously
haven't even bothered to look at the source.
Now its not as if there is any secret how a message loop works in a
Windows GUI application, once the loop is entered, GetMessage()
performs the function or retrieving the data associated with a message
stored in the system message que and if a mesage is available, it
returns with that data copied to a MSG structure.
The message loop then feeds this data through a translation API if
required and then passes the data to a Dispatch API which points the
data at the WndProc associated with the window in the app designated by
the handle member of the MSG structure. This is why the following
statement is nonsense.
> GetMessage *could* be polling.
GetMessage() is not a loop, it is a data retrieval function that is
called in a Windows message loop which is a classic polling loop.
Now as far as trying to defend Donkey's mistakes, Donkey posted the
example himself as the correct way to call a wait state API and that
example was both dangerous and badly designed. I have made perfecly
vaild criticisms of that example and the defects in that example need
to be fixed.
And they were promptly fixed, even though the library function differed
from the one I posted, I did make the change that f0dder pointed out and
closed the thread handle. Something that you have not done in your
library by the way...
shell proc lpfilename:DWORD
LOCAL xc :DWORD ; exit code
LOCAL st_info:STARTUPINFO
LOCAL pr_info:PROCESS_INFORMATION
push edi
; ----------------------------
; zero fill the two structures
; ----------------------------
mov ecx, SIZEOF STARTUPINFO
lea edi, st_info
xor eax, eax
rep stosb
mov st_info.cb, SIZEOF STARTUPINFO ; set the structure size AFTER
; zero filling the rest
mov ecx, SIZEOF PROCESS_INFORMATION
lea edi, pr_info
xor eax, eax
rep stosb
pop edi
invoke CreateProcess,lpfilename,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,
ADDR st_info,
ADDR pr_info
; -------------------------------------------
; loop while created process is still active
; -------------------------------------------
@@:
invoke GetExitCodeProcess,pr_info.hProcess,ADDR xc
invoke Sleep, 0 ; surrender
time slice
cmp xc, STILL_ACTIVE
je @B
ret
shell endp
Note that you create a process but do not close the handles even though
MS documentation says:
> Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.
Sorry, you have a second gaping error in your library code. Oh wait (or
should I say loop), you do not verify that the process has been created
before you enter the loop, what if the exe file does not exist ? Another
third gaping error !!!
I am still waiting for you to point out one in my lib routine...
NOTE GOASM SYNTAX AHEAD
Shell FRAME lpfilename,dwTimeOut
LOCAL Sh_st_info :STARTUPINFO
LOCAL Sh_pr_info :PROCESS_INFORMATION
mov D[Sh_st_info.cb],SIZEOF STARTUPINFO
invoke GetStartupInfoA,ADDR Sh_st_info
mov D[Sh_st_info.lpReserved], 0
invoke CreateProcessA,0,[lpfilename],0,0,0,0,0,0, \
ADDR Sh_st_info,ADDR Sh_pr_info
test eax,eax
jz >.ERROR
:
invoke WaitForSingleObject,[Sh_pr_info.hProcess],[dwTimeOut]
push eax
invoke CloseHandle,[Sh_pr_info.hThread]
invoke CloseHandle,[Sh_pr_info.hProcess]
pop eax
test eax,eax
RET
.ERROR
xor eax,eax
sub eax,1
RET
ENDF
Please, point out any flaws that you find. It is always useful to learn
from the opinions of others. But limit yourself to real flaws, not some
claptrap about AMD K6-2 processors.
Donkey
No - it is blocking because it internally does a blocking wait on the
message queue object. This is very easy to verify - start up notepad
(or any other app that has a single thread and uses GetMessage), as
well as the perfmon.msc performance monitor. Monitor "context switches
per second". You will see that it is zero.. try moving the mouse above
the notepad window, or do anything else that causes messages to be sent
to notepads message queue - you will see that the figure rises above 0.
It would also be pretty appearant if you traced through the calls :)
> Now its not as if there is any secret how a message loop works in a
> Windows GUI application, once the loop is entered, GetMessage()
> performs the function or retrieving the data associated with a message
> stored in the system message que and if a mesage is available, it
> returns with that data copied to a MSG structure.
And if there is no message available, GetMessage *blocks* until a
message is available. "blocking" isn't internet terminology, it is
OS terminology... yes, we have "blocking" and "nonblocking" sockets,
but guess why they're named thus? Just like there is blocking as
well as async file I/O, et cetera.
> The message loop then feeds this data through a translation API if
> required and then passes the data to a Dispatch API which points the
> data at the WndProc associated with the window in the app designated
> by the handle member of the MSG structure. This is why the following
> statement is nonsense.
>
>> GetMessage *could* be polling.
>
> GetMessage() is not a loop, it is a data retrieval function that is
> called in a Windows message loop which is a classic polling loop.
GetMessage has to return if there's a message, and wait until there's
a message if one isn't ready. It could either poll the queue until a
message is ready, or it could block on the queue.
Thus, that statement isn't nonsense. And fyi GetMessage blocks, it
doesn't poll.
> Now as far as trying to defend Donkey's mistakes, Donkey posted the
> example himself as the correct way to call a wait state API and that
> example was both dangerous and badly designed. I have made perfecly
> vaild criticisms of that example and the defects in that example need
> to be fixed.
You made a "bugs in donkey.lib" thread, where you wrote "Until Donkey
fixes these bugs in his library" <etc>. Thing is, Donkey's library isn't
flawed, while the snippet he posted was. If you want to keep this up,
you can comment on the routine Donkey has now posted in this thread,
which is the one in his library.
For a version already published in the MASM32 library, try tis one,
;
«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
align 4
shell_ex proc lpfilename:DWORD,process_priority:DWORD
LOCAL xc :DWORD ; exit code
LOCAL cth :DWORD ; current thread handle
LOCAL cpr :DWORD ; current priority status
LOCAL st_info:STARTUPINFO
LOCAL pr_info:PROCESS_INFORMATION
; ---------------------
; zero fill STARTUPINFO
; ---------------------
mov ecx, 17 ; 68 bytes SIZEOF STARTUPINFO
lea edx, st_info
xor eax, eax
@@:
mov [edx], eax
add edx, 4
sub ecx, 1
jnz @B
mov st_info.cb, 68 ; set the structure size member
invoke CreateProcess,NULL,lpfilename,NULL,NULL,
NULL,NULL,NULL,NULL,
ADDR st_info,
ADDR pr_info
invoke SetPriorityClass,pr_info.hProcess,process_priority
mov cth, FUNC(GetCurrentThread)
mov cpr, FUNC(GetThreadPriority,cth)
invoke SetThreadPriority,cth,THREAD_PRIORITY_IDLE
; -------------------------------------------
; loop while created process is still active
; -------------------------------------------
@@:
invoke GetExitCodeProcess,pr_info.hProcess,ADDR xc
invoke Sleep, 1 ; modified on
suggestion by Jibz.
cmp xc, STILL_ACTIVE
je @B
invoke SetThreadPriority,cth,cpr
invoke CloseHandle, pr_info.hThread
invoke CloseHandle, pr_info.hProcess
ret
shell_ex endp
;
«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
Pssssst, it does not need to be fixed either.
Here is the simplest wait state version in the MASM32 library dated by
American date convention 20/6/2004,
;
«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
align 4
wshell proc lpfilename:DWORD
LOCAL xc :DWORD ; exit code
LOCAL st_info:STARTUPINFO
LOCAL pr_info:PROCESS_INFORMATION
; ---------------------
; zero fill STARTUPINFO
; ---------------------
mov ecx, 17 ; 68 bytes SIZEOF STARTUPINFO
lea edx, st_info
xor eax, eax
@@:
mov [edx], eax
add edx, 4
sub ecx, 1
jnz @B
mov st_info.cb, 68 ; set the structure size member
invoke CreateProcess,NULL,lpfilename,NULL,NULL,
NULL,NULL,NULL,NULL,
ADDR st_info,
ADDR pr_info
invoke WaitForSingleObject, pr_info.hProcess, INFINITE
invoke CloseHandle, pr_info.hThread
invoke CloseHandle, pr_info.hProcess
ret
wshell endp
;
«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
Psssst, this one does not need to be fixed ether.
It does have an unused local in it which I forget to remove but I will
not lose any sleep over it at the moment.
Yet another amazing trasnformation,
Donkey turns to an Ostrich.
----------------------------
==================================
Please, point out any flaws that you find. It is always useful to learn
from the opinions of others. But limit yourself to real flaws, not some
claptrap about AMD K6-2 processors.
==================================
I don't know about old deviant hardware so it does not exist. Microsoft
were wrong according to the Gospel of Donkey when they issued a patch
to fix win95b running on this hardwre.
For someone who follows f0dder in blanket criticisms of someone elses
library design, feel free to get you posted examples right BEFORE you
try and correct someone elses work. You have only has a dose of your
own medicine here and you only appear to be capable of learning by
example.
Blocking means doing something to prevent something else from happening
as in a firewall, socket design etc .... where GetMessage() simply does
not return until it has a message available. Now if you said something
like the GetMessage() function remains "suspended" until a message is
available, you would be coming closer to the mark and this is of course
very easy to do by simply not responding to the function call until
there is a message available.
This statement,
> GetMessage *could* be polling.
is clearly nonsense as GetMessage() does not contain loop code, it is a
data retrieval function, not a polling loop and it is the Windows
messaging system that suspends it by way of not responding to it unless
there is a message to return back to the polling loop.
"blocking" is standard OS terminology. To "block" means to "wait", and
in any decent OS, "blocking" will make sure your thread takes 0% CPU
time until the object that is waited on triggers.
You can differentiate between "poll waiting" and "block waiting", where
"poll waiting" is a cute little CPU-wasting loop like your shell function
uses, and "block waiting" (in windows terms) means removing your thread
from the ready-list and adds it to the object's "trigger me when signaled"
list.
ReadFile, GetMessage, WaitFor*Object, and a lot of other functions, are
all blocking (with the exception of ReadFile in OVERLAPPED mode).
> This statement,
>
>> GetMessage *could* be polling.
>
> is clearly nonsense as GetMessage() does not contain loop code,
It *could* have been constructed like:
while(!DoesQueueHaveMessages(thread.queue)) { /* burn cycles */ }
in which case it would have been polling. That's not how it is
implemented, though - the function checks to see if there's any
desired mesages in the queue; if so, such a message is returned.
If not, the thread enters a blocking wait state until a message
is ready.
> it is a data retrieval function, not a polling loop and it is
> the Windows messaging system that suspends it by way of not
> responding to it unless there is a message to return back to
> the polling loop.
Uh... no. Not that your sentence made much sense. If you're going
to make statements about the internal workings of windows, at
least do yourself the favor of reading "Inside Windows 2000".
It seems like the comedy never ends. As this is an issue that f0dder
has chosen to keep raising for years on end, its humerous to see what
happens when he no longer has the chance to keep raising the issue
because is being raised for him.
The argument on the dependence on polling technology cannot be lost for
a very simple reason, with Von Neuman architecture (read SEQUENTIAL
ACCESS TO INSTRUCTIONS AND MEMORY), current x86 processors just keep
doing "one damned thing after another" but they do it very fast and
with hardware support for task switching so it tends to LOOK LIKE
parallel actions occuring at the same time.
Herein lies the scale of f0dder's confusion.
> ReadFile, GetMessage, WaitFor*Object, and a lot of other functions, are
> all blocking (with the exception of ReadFile in OVERLAPPED mode).
ReadFile() with normal flags does not return until it reads the data
into the supplied buffer, GetMessage() does not return until a message
is available and the Wait state APIs set a system defined wait state
and don't return until the condition has been signalled. The attempt to
generalise across 3 entirely different function types is the indication
of the level of confusion that f0dder suffers with system API calls.
Now f0dder wants to change the subject from the viability of system
defined Wait states to a redefinition of the term "Block(ing)" so that
anything that does not return is a blocking function.
================================
Uh... no. Not that your sentence made much sense. If you're going
to make statements about the internal workings of windows, at
least do yourself the favor of reading "Inside Windows 2000".
================================
Even f0dder should know by now with his penchant for having
consultations with the "colonel" that this data is out of date. None of
the available lists of int 2Eh services are correct for the version of
win2000 SP4 I use because Microsoft intentionally change them from
version to version to slow up the idiot fringe with trojans and
viruses.
I wonder what the next line of waffle from f0dder will bring,
especially as he has wanted to raise this issue over and over again for
a period of years.
And your point is? Forgot about hardware interrupts, perhaps? Ah yes,
you think "interrupt" has something to do with prevention :)
>> ReadFile, GetMessage, WaitFor*Object, and a lot of other functions,
>> are all blocking (with the exception of ReadFile in OVERLAPPED mode).
>
> ReadFile() with normal flags does not return until it reads the data
> into the supplied buffer, GetMessage() does not return until a message
> is available and the Wait state APIs set a system defined wait state
> and don't return until the condition has been signalled. The attempt
> to generalise across 3 entirely different function types is the
> indication of the level of confusion that f0dder suffers with system
> API calls.
...and the three of them have in common that they use blocking wait.
> Now f0dder wants to change the subject from the viability of system
> defined Wait states to a redefinition of the term "Block(ing)" so that
> anything that does not return is a blocking function.
No - anything that does a blocking wait are blocking. This is a pretty
well-defined term.
> ================================
> Uh... no. Not that your sentence made much sense. If you're going
> to make statements about the internal workings of windows, at
> least do yourself the favor of reading "Inside Windows 2000".
> ================================
>
> Even f0dder should know by now with his penchant for having
> consultations with the "colonel" that this data is out of date. None
> of the available lists of int 2Eh services are correct for the
> version of win2000 SP4 I use because Microsoft intentionally change
> them from version to version to slow up the idiot fringe with trojans
> and viruses.
So? "Inside Windows 2000" doesn't list int 2E service numbers, it
describes the general architecture the NT system is based on. One of
the authors of the book is from SysInternals (you know, the guys that
made process explorer among other things), and it's published by
Microsoft Press (those guys really *ought* to know something about the
operating system).
If you read that book, you'd know what "blocking wait" means. And you'd
know that *this* is the basis for the OS, not polling loops. You would
also know that ReadFile is implemented ontop of the asynchronous native
NT API file operation, and that it does a blocking wait to "not return
until file data is read"... among other things.
> And your point is? Forgot about hardware interrupts, perhaps? Ah yes,
> you think "interrupt" has something to do with prevention :)
Lets hear this piece of genius, interrupts occur in a vacuum and no
processor cycles are expended ? Pull the other leg.
> ...and the three of them have in common that they use blocking wait.
You still don't have a difference to other function that does not
return until it has performed its task. I guess under your new found
terminology that there are waits and there are waits ?
> No - anything that does a blocking wait are blocking. This is a pretty
> well-defined term.
The logic is underwhelming, Readfile is "block(ing/ed)" so it cannot
read the data into the assigned buffer ?
I have no prblems with the tools from Sysinternals but I do with your
attempts to re-interpret an OS on the basis of your own prejudice
against certain techniques. No matter how long you waffle in high level
fantasy land, a Von Neuman architecture machine (read SEQUENTIAL ACCESS
TO INSTRUCTIONS AND MEMORY) does not work the way you wish to describe
it.
> ReadFile is implemented ontop of the asynchronous native NT API file operation
Translate this waffle as "Read in a thread" and take note that a HDD
reads one block of data at a time, not asynchronous parallel streams.
You can simulate multiple asynchronous reads but you thrash the disk
for the privilege.
Your reference material is out of date, like it or lump it as Microsoft
regularly change very low level stuff like int 2Eh services from
version to version to make life difficult for the viral idiot fringe.
The other factor is at about 5 years old then the development time for
win2k, you are hardly leading edge here. Until you comprehend the
sequential nature of current hadware, you will continue to flounder
around in high level fantasy land.
Technically, the correct term is synchronous. There is no guarantee
that it blocks. Further, the GetMessage loop might *actually* be
polling if it sitting there looking for a specific message and throwing
all the others away (or passing them on) if the specific message does
not come along. If it followed the *true* concept of blocking, it would
only be awoken when the actual message(s) it wants to process are
avaiable. No sense, for example, having the WndProc wake up (after a
context switch) if the code isn't actually going to act on the message.
This is what is wonderful about things like WaitForObject versus
GetMessage.
The fact that GetMessage may block doesn't mean polling can't occur.
We've been through this before...
Cheers,
Randy Hyde
GetMessage removes your thread from the ready-list if there isn't any
message available. Yes, messages other than the ones your wndproc handle
will be dispatches, but GetMessage itself blocks until there's a message
in the queue.
Of course not - they're generated from an external source, and the
interrupt processing does take some CPU time. A blocking thread isn't
even considered for scheduling, though, so a blocked thread doesn't
use any time in any interrupt handlers.
>> ...and the three of them have in common that they use blocking wait.
>
> You still don't have a difference to other function that does not
> return until it has performed its task. I guess under your new found
> terminology that there are waits and there are waits ?
You have two ways of "not returning until the task is performed".
You can either poll for completion status, or you can block and
be waked up when the event triggers.
>> No - anything that does a blocking wait are blocking. This is a
>> pretty well-defined term.
>
> The logic is underwhelming, Readfile is "block(ing/ed)" so it cannot
> read the data into the assigned buffer ?
That's not what I was saying.
> I have no prblems with the tools from Sysinternals but I do with your
> attempts to re-interpret an OS on the basis of your own prejudice
> against certain techniques.
This is not any form of re-interpretation, it's facts as stated in
Inside Windows 2000, and from what can be seen if you trace, disassemble,
or even look at the right performance monitoring tools.
>> ReadFile is implemented ontop of the asynchronous native NT API file
>> operation
>
> Translate this waffle as "Read in a thread" and take note that a HDD
> reads one block of data at a time, not asynchronous parallel streams.
> You can simulate multiple asynchronous reads but you thrash the disk
> for the privilege.
Ever heard of DMA transfers?
Appearantly not.
Sure, but the fact that blocking has occurred *somewhere* up the line
doesn't mean that polling has not occurred. Let's go back the the
simple example:
someLabel:
mov al, SomeLocation
test al, 1
jnz someLabel
Obviously, this is polling. But suppose accessing SomeLocation causes a
page fault and the OS is smart enough *not* to return control to this
code until the value of SomeLocation actually changes? If bit #3
changes, and bit #1 is a one, the loop repeats and the code reblocks on
the access of SomeLocation (until SomeLocation changes again).
This is really no different than a spin that loops until some IRQ
clears the L.O. bit of SomeLocation; except, of course, the page fault
version is probably more efficient (if the bit changes slowly).
Now a *blocking* (versus polling) version of this would be the case
where the OS doesn't return control to this code sequence until bit #0
contains a zero.
Cheers,
Randy Hyde
I really don't wish to discuss this at a semantic basis :)
The thing that *matters*, here, is that GetMessage removes your thread
from the ready-list when there aren't any messages in the queue, and
that the thread will cause no CPU usage until a thread enters the queue.
The obvious fact is that if the OS wasn't based mainly on blocking
waits, but did polling/spinloops/whatever all the time, you would be
in performance hell.
Semantic = meaning.
If we don't discuss it at a semantic level, then what's to discuss?
>
> The thing that *matters*, here, is that GetMessage removes your thread
> from the ready-list when there aren't any messages in the queue, and
> that the thread will cause no CPU usage until a thread enters the queue.
And what if there are a steady stream of messages, none of which your
app is interested in handling?
>
> The obvious fact is that if the OS wasn't based mainly on blocking
> waits, but did polling/spinloops/whatever all the time, you would be
> in performance hell.
Then you would be in performance hell (constantly polling for the
messages you want). Sure, the overhead of Windows would *swamp* the
overhead of your polling code, but that's not a defense (it is, in
fact, exactly the defense Hutch is using in his polling vs.
WaitForSingleObject argument).
The fundamental problem here is that people confusing what "polling"
versus "not polling" means. The opposite of "polling" is
"interrupt-driven", not "event-driven". True, interrupts are events
and, therefore, we can claim that all interrupt code is event-driven,
but it is perfectly possible to create and handle events in a polling
environment, too (keep in mind, a bit state changing on an input port
is an example of an "event").
The opposing of "blocking" is "non-blocking" and this does *not* imply
polling occurs. The concepts of "polling/interrupts" and
"blocking/non-blocking" are othogonal. "blocking" is not the opposite
of "polled". This, I think, is where your confusion lies. Hutch's real
problem is *not* that he's doing polling, per se, but that he is not
remaining blocked until the process terminates (he is, of course,
blocking, but is constantly being unblocked prior to the completion of
the routine if it runs for any length of time). If we modified Hutch's
algorithm, somehow, so that it blocked whenever he tested the process'
return code (e.g., using a page fault), then his current code would be
*just* as efficient, all the way around, as WaitForSingleObject. It
would also use blocking, and because it tests the return result to see
if the process is complete, it arguably still does polling (though even
I would admit that this is stretching the definition as the return
result would always be "it's finished").
GetMessage is a great example of an event-driven routine. It's
*synchronous*, meaning that it doesn't come back until an event
actually occurs, but whether it blocks or sits in some loop handling
other chores until an event occurs is irrelevant.
If you're going to argue the fine details of whether polling is good or
bad (e.g., when waiting for some other process to quit), it's important
that you make *sure* you're on solid ground when using terms like
"polling" and "blocking". Traditionally, polling has meant spin-loops
and low performance. There is, however, no requirement that this be the
case. Again, the terms "interrupt driven/polled" and
"blocking/nonblocking" are orthogonal. You can have "interrupt-driven,
blocking" and "interrupt-driven, non-blocking" and you can also have
"polled, blocking" and "polled, non-blocking".
Cheers,
Randy Hyde
>> The thing that *matters*, here, is that GetMessage removes your
>> thread from the ready-list when there aren't any messages in the
>> queue, and that the thread will cause no CPU usage until a thread
>> enters the queue.
>
> And what if there are a steady stream of messages, none of which your
> app is interested in handling?
You will have to handle (well, pass to DefWindowProc) those, of course.
But the thread *will* block while there's no messages in the queue,
and unless you have a bad-behaving app that does a load of broadcast
posts, a typical app will be in a blocking GetMessage call.
perfmon.msc lets you see "Thread State" and "Thread Waiting Reason".
I'll try finding out how to convert the numerics to meaningful text,
there's probably some defines in the NT DDK. Anyway, the main (and only)
thread of notepad not doing anything is in thread state "5", with the
wait reason "13" on my XP SP2 :)
> The opposing of "blocking" is "non-blocking" and this does *not* imply
> polling occurs. The concepts of "polling/interrupts" and
> "blocking/non-blocking" are othogonal. "blocking" is not the opposite
> of "polled". This, I think, is where your confusion lies.
Probably... I'm not confused, but I might be using wrong terminology :)
What it boils down to is that GetMessage and a lot of other API functions
block, using 0% CPU time, until their wait condition is satisfied. And
most of this doesn't require interrupt time either, because of way the
kernel is constructed.
> GetMessage is a great example of an event-driven routine. It's
> *synchronous*, meaning that it doesn't come back until an event
> actually occurs, but whether it blocks or sits in some loop handling
> other chores until an event occurs is irrelevant.
Except for performance reasons - and I can assure you that it blocks.
(If you have a timer associated with your message queue things do get
a bit more complicated, and a little extra time has to be spent by the
scheduler - but the thread is still removed from the ready-list, and
is still blocking).
> If you're going to argue the fine details of whether polling is good
> or bad (e.g., when waiting for some other process to quit), it's
> important that you make *sure* you're on solid ground when using
> terms like "polling" and "blocking".
Yes, I should be more pedantic about the definitions. Problem is that
I haven't done any OS courses yet, and "teh intarnet" references are
using pretty loose definitions.
> Traditionally, polling has meant
> spin-loops and low performance. There is, however, no requirement
> that this be the case. Again, the terms "interrupt driven/polled" and
> "blocking/nonblocking" are orthogonal. You can have "interrupt-driven,
> blocking" and "interrupt-driven, non-blocking" and you can also have
> "polled, blocking" and "polled, non-blocking".
In the case of a MessageLoop... the user code keeps *polling* GetMessage.
GetMessage *blocks* until there's a message in the queue. I'm afraid you
can't easily classify how the wake-ups are being done, though. The NT
scheduler isn't an entity that you can easily isolate, it's pretty much
spread all over the place. Ie, if one thread sends a message that is
destined for another thread's message queue, this will wake up the
target thread from it's slumber.
<snip>
>In the case of a MessageLoop... the user code keeps *polling* GetMessage.
>GetMessage *blocks* until there's a message in the queue.
That may be the best description I have heard yet.
<snip>
--
ArarghMail509 at [drop the 'http://www.' from ->] http://www.arargh.com
BCET Basic Compiler Page: http://www.arargh.com/basic/index.html
To reply by email, remove the garbage from the reply address.
Actually, the getMessage call is *not* the polling part. Consider a
typical message loop:
somelabel:
<call get message>
<check the message to see if it's one we handle>
<handle it if so>
<pass it on if not>
<repeat all the above>
The polling that takes place is in the <check the message...> logic.
Compare this with a "traditional" polling loop:
somelabel:
call GetAValueIntoAL
test al, 1
jz somelabel
We don't know how GetAValueIntoAL operates, nor do we really care. We
don't know how long it takes to execute, whether it blocks or whether
it runs continuously. All we know is that when we get back from this
call we aren't necessarily going to go about our business. We're going
to *check* the return result to see if we've got to wait for additional
data before proceeding. The same is true in the getMessage loop. An
event occurs, our code is activated, we check to see if it's an event
we handle, and if not we return control to the system (perhaps through
some convoluted path) and wait for the next event to come along that we
can check.
Now a *non-polling* version of this could be written if we could tell
Windows beforehand exactly *which* events we are going to handle. Then
Windows would *only* activate our code when one of our events occurs.
Some might argue that all we've done is move the polling somewhere else
-- and that would be exactly right. "Polling" vs. "interrupt" driven
operation is from the point of view of the process. For example,
consider this example I've given many times:
IRQ:
mov hadIRQ, 1
iret
.
.
.
mov hadIRQ, 0
someLoop:
cmp hadIRQ, 0
je someLoop
>From the perspective of the main thread, this is a polling loop. OTOH,
from the perspective of the IRQ handler, this is an interrupt-driven
system. Note that no blocking occurs here. We could just as easily
have blocking by doing the following:
IRQ:
call unblockProcess
iret
.
.
.
call blockProcess ;Wait here to be unblocked.
A Windows WndProc message loop is a hybrid of this (typically). You get
something like the following:
IRQorOtherEvent:
mov eax, eventCode
call unblockProcess
.
.
.
.
.
.
messageLoop:
call blockProcess ;(e.g., getMessage)
cmp eax, eventCodeWeWant
jne messageLoop
<<handle our event>>
If the event code is *not* one we want, we've unblocked for no good
reason. We check the event code (poll it) and block until the next
event if it's not one we're interested in. The fact that "blockProcess"
has possibly blocked doesn't change this fact. It's really no different
than this:
someLoop:
call SleepForOneSecond
in al, somePort
test al, 1
jz someLoop
The fact that this code blocks (by sleeping for one second) doesn't
change the fact that it's a polling loop. It's a more efficient polling
loop as it doesn't burn up CPU cycles constantly, but a polling loop
nonetheless (I'm assuming, of course, that SleepForOneSecond actually
blocks rather than spins in this case). A typical Windows message loop
in a WndProc works pretty much the same way.
Cheers,
Randy Hyde
> The fact that this code blocks (by sleeping for one second) doesn't
> change the fact that it's a polling loop. It's a more efficient
> polling loop as it doesn't burn up CPU cycles constantly, but a
> polling loop nonetheless (I'm assuming, of course, that
> SleepForOneSecond actually blocks rather than spins in this case). A
> typical Windows message loop in a WndProc works pretty much the same
> way.
Yeah - except that it doesn't wake up at regular time intervals, it
only wakes up when there's one message or another. Sure, you can
argue that it would be better if it only woke up when there's a
message for it to handle, but then this checking code would have to
be moved elsewhere.
Since a lot of message processing code is done in usermode, it's not
like it's a big performance deficiency to go through the user wndproc
and then to defaultwndproc.
The thing that *is* a big performance benefit, though, is that the
wndproc is only unblocked when there's a message. A thread can
remain in this blocked state for a long time without receiving any
messages, and thus taking no CPU time whatsoever.
Oh, there is no question about the performance of the whole thing. But
then again, performance isn't considered in the definition of polling.
People have traditionally associated slow performance with polling, but
that isn't necessarily so (and even *you* must admit that Steve's
numbers aren't *that* bad; even if they could be zero, it's not like
he's wasting a tremendous amount of time polling ['cause he's blocked
most of the time]). Indeed, there are some cases (e.g., when you
consider interrupt latency) where polling is actually *faster* than an
interrupt-driven system. Steve's example, however, is not such a case.
No matter how little time he claims to be wasting, he *is* wasting some
time that could be saved by being blocked until the process he is
waiting on terminates.
Cheers,
Randy Hyde
Yup, yup and yup :)
I still prefer 0% when I can get it without any disadvantages, and boy
there were *bad* performance problems before he added the Sleep, and
they were still bad before he changed the sleep parm from 0 to 1.
> Indeed, there are some cases (e.g., when you consider interrupt latency)
> where polling is actually *faster* than an interrupt-driven system.
Yup, not going to disagree with this either.
> Steve's example, however, is not such a case.
Which is correct too :)
It's a bit hard defining exactly what kind of behaviour
WaitForSingleObject is, because if you're nitpicky *everything* boils
down to the timer IRQ... but the kernel interactions are pretty
intricate.
> No matter how little time he claims to be wasting, he *is* wasting
> some time that could be saved by being blocked until the process he is
> waiting on terminates.
Yup. And his argument that with WaitForSingleObject this time would
be wasted in the interrupts instead is plain wrong.
>
> someLoop:
> call SleepForOneSecond
> in al, somePort
> test al, 1
> jz someLoop
>
> The fact that this code blocks (by sleeping for one second) doesn't
> change the fact that it's a polling loop. It's a more efficient polling
> loop as it doesn't burn up CPU cycles constantly, but a polling loop
> nonetheless (I'm assuming, of course, that SleepForOneSecond actually
> blocks rather than spins in this case). A typical Windows message loop
> in a WndProc works pretty much the same way.
> Cheers,
> Randy Hyde
It's difficult to know where to snip this! So I've just concentrated on
the last point.
Remember that WndProc is the "polling" loop; DispatchMessage is
responsible for scheduling the the windows procedure itself. To
demonstrate that the scheduler is re-entered by DispatchMessage, try
and process the windows messages in the WndProc itself; or, dispatch
the windows procedure yourself by doing a GetWindowLong for
GWL_WNDPROC, and calling it with the appropriate hwnd etc.
You'll find that all sort of wierd things happen, as (for instance)
timer callbacks don't get scheduled properly. They appear to be
"injected" by DispatchMessage; there appear to be more messages handled
by the windows procedure than there are by the WndProc itself. WndProc
is just one source of events.
The windows procedure is therefore event driven by DispatchMessage,
regardless of whether WndProc appears to be a polling loop or not.
Caveat; of course, much of this is speculation based on inspection of
the effects of writing this kind of stuff, as the source is locked away
in a safe in Redmond.
--
Regards
Alex McDonald
===============================
You have two ways of "not returning until the task is performed".
You can either poll for completion status, or you can block and
be waked up when the event triggers.
===============================
There has always been another approach and that is to simply leave a
procedure without responding to it and if you give it no processor time
nothing happens. The procedure is suspended until it is activated again
and this is neither polling nor blocking.
You could emulate this capacity at high level with the EnableWindow()
API and simply turn the window off until you want it to do something
but this always assumes something else that is alive that can "wake it
up" again. Such a high level implimentation would be very inefficient
in comparison to what an OS should be doing but it is a viable model of
what does happen.
There is no doubt that a message loop polls the return value of
GetMessage() and also uses the message data in the MSG structure for
translation where required and dispatching to the WndProc and it is
equally not in doubt that GetMessage() simply does not return unless
there is a message in the application message que.
There is no reason to assume a blocking condition when there is no need
to do it this way as the OS already has the capacity to just leave the
call and do nothing until a message is available.
The original noise about polling loops started some years ago with a
"shell" procedure I published in a library. Something that appears to
have been missed is that the design of a "shell" procedure on x86
hardware comes from well before 1990 when you stopped one running
application and ran another and when the called app terminated, control
went back to the caller with the option of an exit code from the
terminated app.
Neither then nor now do matters of synchronisation matter in this
context even though the reason why are very diferent as it is a two app
relationship. With non-reentrant OS versions, you did not have to worry
about asynchronous application in seperate processes but with the
advent of commonly available multitasking OS versions, when you
suspended something, you always yielded unused time back to the OS so
it could do someting else.
When NTOSKRNL has a function ZwYieldExecution() its not as if anything
has changed much in this area as an OS under the hood still had to do
very similar things. This yield function is not normally available to
application programs and the old Sleep() or SleepEx() APIs are about as
close as you can get allowing that there is some error in the existing
documentation about setting the duration to ZERO.
It only conditionally yields depending on the priority of other running
processes so you have to fudge it by setting a duration above zero but
below the average time slice duration to force a yield.
The contrast between a polling loop and a system defined wait state
breaks down to flexibility. If you can perform the task by setting a
wait state, then do it but if you want to add extra capacity like
testing a user key input or updating the clock or dispatching a message
or any of a multitude of things that are done on a periodic basis, you
can forget prebuilt wait states and easily write a polling loop that
does all of these things in an easy, flexible and efficient way.
Any operation n a computer takes processor cycles so its naive to
assume that you can get anything for nothing so instead of making
incorrect assumptions, face that any code has a cost and be efficient
in writing it. If a system defined wait state will do the job, use it
but when they are clunky, inflexible, badly documented and the like,
there is a viable alternative that can do all of these things wel if
its writen well.
Is easy to write a bad polling loop, just poll GetTickCount() without
yielding for any duration you have in mind and you will see very high
processor usage but its not much harder to do it properly and get
immeasurably small processor percentages for each polling loop and you
can do almost anything with one.
Yawn, do you just cut and paste ?
More and more you are looking like Betov.
Donkey
Donkey
Your use of the term "procedure" is incorrect and
confusing. A procedure is a piece of code, nothing
more. In particular, there is no guarantee of an
execution context. "Suspending" a procedure, I suppose,
happens when it returns to its caller. Maybe you could
consider a call to a different procedure a "suspension"
of the procedure. But none of this makes any real
sense. Execution units are processes and threads. But
substituting these two words for "procedure" in the
paragraph above still makes little sense.
You need to explain the previous paragraph a bit better
before I could comment on it.
> You could emulate this capacity at high level with the
> EnableWindow() API and simply turn the window off until
> you want it to do something but this always assumes
> something else that is alive that can "wake it up"
> again. Such a high level implimentation would be very
> inefficient in comparison to what an OS should be doing
> but it is a viable model of what does happen.
???
>
> There is no doubt that a message loop polls the return
> value of GetMessage()
Okay, so far I agree with you on this.
> and also uses the message data in
> the MSG structure for translation where required and
> dispatching to the WndProc and it is equally not in
> doubt that GetMessage() simply does not return unless
> there is a message in the application message que.
Yes.
>
> There is no reason to assume a blocking condition when
> there is no need to do it this way as the OS already
> has the capacity to just leave the call and do nothing
> until a message is available.
"do nothing" generally means "blocked" within the
context of a process or thread.
>
> The original noise about polling loops started some
> years ago with a "shell" procedure I published in a
> library.
Yes, if I what I've been told is correct, f0dder
pointed out to you back then that WaitForSingleObject
(WFSO) was a better solution and the war began. Okay.
> Something that appears to have been missed is
> that the design of a "shell" procedure on x86 hardware
> comes from well before 1990 when you stopped one
> running application and ran another and when the called
> app terminated, control went back to the caller with
> the option of an exit code from the terminated app.
Sounds like DOS to me. But even if you wrote this code
before the availability of WFSO, that doesn't excuse
you from using it once the capability is available or
its availability is made known to you. The problem is
that you took this suggestion as an affront to your
intelligence and, in a Betovian style, proceeded to
defend your mistake out of some sort of misplaced
pride. To this day you waste considerable effort trying
to "prove" that what you did is okay, when it's obvious
to everyone that WFSO is a superior solution.
>
> Neither then nor now do matters of synchronisation
> matter in this context even though the reason why are
> very diferent as it is a two app relationship.
Forget synchronization. For the trivial apps you've
written, it's not that important. What matters is that
WFSO is easier and it's more efficient. What's to
discuss beyond that?
> With
> non-reentrant OS versions,
Such as? Are you talking about DOS?
> you did not have to worry
> about asynchronous application in seperate processes
> but with the advent of commonly available multitasking
> OS versions, when you suspended something, you always
> yielded unused time back to the OS so it could do
> someting else.
Okay. But then why consume any time at all if you have
no work to do?
>
> When NTOSKRNL has a function ZwYieldExecution() its not
> as if anything has changed much in this area as an OS
> under the hood still had to do very similar things.
> This yield function is not normally available to
> application programs and the old Sleep() or SleepEx()
> APIs are about as close as you can get allowing that
> there is some error in the existing documentation about
> setting the duration to ZERO.
Giving up a time slice is a very valuable thing to do
in many applications. You do some work, and then you
block because you're nice and you don't want to consume
CPU cycles when you don't need them. Great idea.
So why do you keep defending the idea of being woken
up, wasting CPU cycles, when there is absolutely no
need to do so? Why not just give up the CPU entirely
until you actually need it? And, in the program in
question, that would be when the other process
terminates. And this is exactly what WFSO does for you.
To put it in terms you can understand, it's something
like this:
sleep( untilOtherProcessTerminates );
No polling. No wasted instructions. No context
switches. No blown cache lines. And better latency
(your app runs as soon as possible after the process
terminates, not up to a minimum of 1msec later).
>
> It only conditionally yields depending on the priority
> of other running processes so you have to fudge it by
> setting a duration above zero but below the average
> time slice duration to force a yield.
Why are you running at all? Why not just block until
the other process terminates?
>
> The contrast between a polling loop and a system
> defined wait state breaks down to flexibility.
What is this "flexibility" needed for? You're not doing
anything but burning cycles in your polling loop
everytime you wake up. What would you use this
flexibility for?
And should you *really* need to do other processing in
the future, well, that's what threads are all about.
And if for some reason you *really* need a message sent
to your WndProc loop announcing the completion of your
other process, just start a thread that does a WFSO
until the process quits, then *that* thread sends the
message (in perfect synchronization) and then
terminates. In the meantime, your WndProc is still
chugging away so your window isn't frozen. And you can
be doing any other processing you like.
> If you
> can perform the task by setting a wait state, then do
> it but if you want to add extra capacity like testing a
> user key input or updating the clock or dispatching a
> message or any of a multitude of things that are done
> on a periodic basis, you can forget prebuilt wait
> states and easily write a polling loop that does all of
> these things in an easy, flexible and efficient way.
Actually, it's far more flexible to use threads for
each of these purposes. Start a thread (using sleep for
example) that counts of time and either directly
updates the clock or sends a message to your WndProc
code to update the clock. Start a different thread to
wait for your other process to complete. Start any
number of threads to do all the background processing
you need done. And use your main thread to process all
the Windows messages. THAT'S flexible. With a polling
loop, you have to put in all kinds of states to test
for this condition and that condition. It becomes
spaghetti code *real* quick. And it becomes difficult
to maintain and quite *INFLEXIBLE*. OTOH, using
separate threads for each of these activities
simplifies each task and the correct execution of each
thread depends *very little* on the execution of the
other threads. Very efficient. Very flexible. Very easy
to maintain (assuming, of course, you know a little bit
about concurrent programming).
Granted, someone who doesn't know the first thing about
threads and concurrency may find the polling scheme
easier to comprehend early on. But as such systems
grow, they tend to get out of control.
I'm not going to tell you that concurrent programming
is a piece of cake; but if what you're doing is
concurrent processing, your life will be a whole lot
simpler if you use the concurrent programming model.
This is not to say that polling will never be better in
some special cases, but those *would* be special cases.
>
> Any operation n a computer takes processor cycles so
> its naive to assume that you can get anything for
> nothing so instead of making incorrect assumptions,
> face that any code has a cost and be efficient in
> writing it. If a system defined wait state will do the
> job, use it but when they are clunky, inflexible, badly
> documented and the like, there is a viable alternative
> that can do all of these things wel if its writen well.
WFSO is very well documented. It is the basis of many
Windows applications. Are you suggesting it is
inefficient? Do you have proof of this? And as "badly
documented" as it may be, I've yet to see a description
of your polling approach in the MSDN.
>
> Is easy to write a bad polling loop, just poll
> GetTickCount() without yielding for any duration you
> have in mind and you will see very high processor usage
The fact that sleep(1) uses *fewer* CPU cycles doesn't
change the fact that you can use almost *none* by
calling WFSO instead.
> but its not much harder to do it properly
Actually, it's *easier* to do it properly. The call to
WFSO is *less* work than your polling loop.
> and get
> immeasurably small processor percentages for each
> polling loop and you can do almost anything with one.
One word for you: latency. The larger you make the
parameter you pass to sleep, the fewer cycles you
consume; but it's also the case that you push the
latency of your response out, too. And that's ignoring
all the context switching and caching issues that
f0dder has raised many times.
Cheers,
Randy Hyde
Certainly not in this argument.
As I've said many times in this very thread, the problem is that people
are confusing two orthogonal (independent) concepts: "blocking versus
non-blocking" and "polling versus interrupt-driven". The argument
around here seems to be "polling versus blocking" but this is
*literally* an apples to oranges comparison. You *can* have blocking
and polling in the same code, as you go on to point out.
> I prefer a more explicit term. I
> beleive that the "polling loop" that Hutch posted (shell) and the
> GetMessage loop are equivalent in the following sense; both loops are
> Spin-Wait loops,
Well, not really. "Spin-xxxx loop" generally means you do *not* give up
the processor. But okay.
> the difference lies in the type of wait. One waits for
> a specific unchanging interval to expire (Sleep(1)) and the other waits
> for an event (a message entering the queue).
Precisely. And the difference is that Hutch's polling loop has to
respond to *many* more events (typically; one per msec in theory at
least) than the WaitForSingleObject (WFSO) approach (which has only one
event).
> Other than that deceptively
> small difference, there is no real logical divergence. However that
> difference is at the root of all of the threads that Hutch has seen fit
> to infect this newsgroup and others with. Almost any programmer can see
> the advantage to waiting on an event rather than continually asking if
> it has happened yet, I cannot see the validity in any argument to the
> contrary. Event signalled Spin-Wait loops are always the best way when
> the function is available.
Especially when they are less code and easier to use than the polling
loop. I keep asking, "What's the aversion to using WFSO?" Thus far,
Hutch has not answered this question. I hear a nebulous "it's more
flexible." But that doesn't apply to the current situation. No such
flexibility is necessary.
Cheers,
Randy Hyde
Remove thread from ready-list = 0% CPU usage. Call it blocking or
call it something else, this is what the Wait*Object, GetMessage,
ReadFile, WriteFile, recv, send (et cetera) routines do.
> You could emulate this capacity at high level with the EnableWindow()
> API and simply turn the window off until you want it to do something
> but this always assumes something else that is alive that can "wake it
> up" again. Such a high level implimentation would be very inefficient
> in comparison to what an OS should be doing but it is a viable model
> of what does happen.
EnableWindow doesn't really have anything to do with this - whether
mouse and keyboard is enabled or not, there's still a lot of other
messages.
> There is no doubt that a message loop polls the return value of
> GetMessage() and also uses the message data in the MSG structure for
> translation where required and dispatching to the WndProc and it is
> equally not in doubt that GetMessage() simply does not return unless
> there is a message in the application message que.
Wow, a whole sentence that is correct :)
> There is no reason to assume a blocking condition when there is no
> need to do it this way as the OS already has the capacity to just
> leave the call and do nothing until a message is available.
"leaving the call" means putting removing the thread from the ready
list. Either that, or entering a spinning loop. Fortunately,
Microsoft were wise enough to block. This is easy to verify with
any tool that shows the current thread state.
sysinternals' Process Explorer can show this, too. Launch notepad,
find it in the proces list, right-click and choose properties,
select the "threads" tab. One thread, sate: "Wait:WrUserRequest".
This means it's blocking in GetMessage.
> The original noise about polling loops started some years ago with a
> "shell" procedure I published in a library. Something that appears to
> have been missed is that the design of a "shell" procedure on x86
> hardware comes from well before 1990 when you stopped one running
> application and ran another and when the called app terminated,
> control went back to the caller with the option of an exit code from
> the terminated app.
DOS style shell routines() used exactly 0% CPU, since DOS was single
threaded. That way, you can say that your original shell() routine
wasn't an exact emulation of original dos-style shell() routines :)
> Neither then nor now do matters of synchronisation matter in this
> context even though the reason why are very diferent as it is a two
> app relationship. With non-reentrant OS versions, you did not have to
> worry about asynchronous application in seperate processes but with
> the advent of commonly available multitasking OS versions, when you
> suspended something, you always yielded unused time back to the OS so
> it could do someting else.
Why yield in a less efficient way that has less correct
synchronization, when there's no penalties and only benefits from
doing it "the right way"? Moot point, I guess - the gospel according
to hutch.
> When NTOSKRNL has a function ZwYieldExecution() its not as if anything
> has changed much in this area as an OS under the hood still had to do
> very similar things. This yield function is not normally available to
> application programs
SwithToThread available since NT4.
> and the old Sleep() or SleepEx() APIs are about as close as you can get
> allowing that there is some error in the existing documentation about
> setting the duration to ZERO.
What error? "A value of zero causes the thread to relinquish the
remainder of its time slice to any other thread of equal priority that
is ready to run." - that should make it perfectly clear it won't yield
to lower-priority threads.
> The contrast between a polling loop and a system defined wait state
> breaks down to flexibility. If you can perform the task by setting a
> wait state, then do it
Indeed, it's the most efficient way to wait. (Unless of course doing
something RTOS-ish and need very low latency... but then you wouldn't´
(shouldn't) be programming for windows anyway.)
> but if you want to add extra capacity like testing a user key input or
> updating the clock or dispatching a message or any of a multitude of
> things that are done on a periodic basis, you can forget prebuilt wait
> states and easily write a polling loop that does all of these things in
> an easy, flexible and efficient way.
Or you could WaitForMultipleObjectsEx to be more efficient, with the
added benefit that I/O completion ports and APCs can be serviced.
(I'm not sure whether IOCP and APCs can be serviced while in a Sleep()
wait state or not - would be worth checking in IW2000.)
> Any operation n a computer takes processor cycles so its naive to
> assume that you can get anything for nothing so instead of making
> incorrect assumptions,
"hutching" for process termination has some more or less fixed
overhead, as well as (child-process-duration / SleepTime) * more-or-
less-fixed-duration overhead, whereas WaitForSingleObject has
more-or-less-fixed-duration overhead which is guaranteed to always
be smaller than the "hutching" wait.
> face that any code has a cost and be efficient in writing it. If a
> system defined wait state will do the job, use it but when they are
> clunky, inflexible, badly documented and the like,
clunky? how. Inflexible? They let you wake up on a lot more conditions
than Sleep. Badly documented? Hardly.
> Is easy to write a bad polling loop, just poll GetTickCount() without
> yielding for any duration you have in mind and you will see very high
> processor usage but its not much harder to do it properly and get
> immeasurably small processor percentages for each polling loop and you
> can do almost anything with one.
And it's a single line of code to WaitForSingleObject with 0% CPU
overhead while the child app is running, with the additional benefit
of being as perfectly synchronized to child app termination as you can
be without resorting to a kernel-mode driver.
Yup, that letter will get things rolling.
Phil
--
If a religion is defined to be a system of ideas that contains unprovable
statements, then Godel taught us that mathematics is not only a religion, it
is the only religion that can prove itself to be one. -- John Barrow
In your case, a "d" (if I get the joke).
--
Regards
Alex McDonald
I will address the list of consideration when I am a bit more awake but
I do have an unrelated comment to make.
If the issue of polling version WaitForSingleObject(Ex) was anything
like an efficiency issue, it would be something to worry about but the
tested percentages are so small they are hard to measure with very
unusual test pieces.
A few years ago I designed a dispatching technique for a WndProc and
similar procedures that used a very old mainframe technique, a
dynamically loaded jump table and for any message in the WndProc, it
only ever took a memory access to the table and one jump to get to the
message.
Benchmarking the method showed it was about 10 time faster than a
standard switch block and as the switch block gets larger it gets
slower where te jump table was close enough to constant in speed.
Now the speed difference was gained by simply doing a lot less work and
while it is hardly a recommended practice in MSDN, it reduced te
instruction count in processing messages in a WndProc by enough to drop
the output file size by a section.
While the technique is clearly a lot more efficient, a normal WndProc
switch block or similar sequential comparison method works well enough
not to bother, even though it means wasting cycles for evey message
that is passed through a WndProc which is a reasonable number for any
working Window that has the focus.
Now in comparison a "shell" procedure of the historical type that runs
and external app while disabling the caller is a rarely used incidental
function and I could live with 1% processor usage for almost every task
I have ever used one for but as a matter of fact, it uses far less. I
have some idea of its processor uage purely by running a very unusual
test of 1000 threads to get it to even measure someting and the results
are something less than one 200th of one percent for each running
thread.
Now put this into the context of about 99.99999999% of applications
being GUI applications and the contrast is there to make. Its fine to
waste processor cycles with less than efficient WndProc functions but
heaven forbid writing someting as efficient as a polling loop that uses
less than one 200th of one percent.
This is why I see the tecnical considerations as a storm in a teacup
and the near endless noise about the imaginary gains of doing something
different being driven for reasons not related to peformance or
functionality. With the scale of appallingly inefficient commercal slop
coming out of current compilers with an ever growing list of
dependencies, memory demands and any other crap plugged in, one 200th
of one percent or less is hardly headline making material.
[lots of explanation snipped]
>
> Now put this into the context of about 99.99999999% of applications
> being GUI applications and the contrast is there to make. Its fine to
> waste processor cycles with less than efficient WndProc functions but
> heaven forbid writing someting as efficient as a polling loop that uses
> less than one 200th of one percent.
But this is the problem. The *one* application we're discussing is an
example of that 0.000000001% of the applications that are *not* GUI
apps.
No one, myself and f0dder included, have ever said that polling is
*never* appropriate. What we're saying is that your "wait for the
process to complete polling loop" is inappropriate. WaitForSingleObject
(WFSO) is a much better solution in this case.
Now if you morph your program into something else, that requires
periodic updates or computations, then perhaps your "sleep" solution
might be appropriate. But for the code you're posting, it is *not*
appropriate.
Put another way, polling (as you're doing) is probably inapprorpriate
99% of the time when waiting on another process to complete.
>
> This is why I see the tecnical considerations as a storm in a teacup
> and the near endless noise about the imaginary gains of doing something
> different being driven for reasons not related to peformance or
> functionality.
Yet you are the one constantly whipping up the storm with all these
threads you create all the time. Here, on the Win32ASM board, and even
on the MASMForum board.
> With the scale of appallingly inefficient commercal slop
> coming out of current compilers with an ever growing list of
> dependencies, memory demands and any other crap plugged in, one 200th
> of one percent or less is hardly headline making material.
As we all know, a few cycles here, a few cycles there. It all adds up
after a while. While a *good* programmer knows when performance is
important and when not to worry about it, the argument against polling
in your case is not so much performance as it is that polling is more
complex, more difficult to maintain, requires more code, and is a bit
less efficient. Again, I ask, what's the problem with just using WFSO
for you little "shell" application? There is no need whatsoever for
polling.
Cheers,
Randy Hyde
Noting that the OS at it base uses polling technology and at it core
messaging system it uses polling technology, a vast majority of the
comments that have been passed about polling are garbage. Testing
exceeds opinion every time and testing show that polling when written
correctly tests well.
=========================
As we all know, a few cycles here, a few cycles there. It all adds up
after a while. While a *good* programmer knows when performance is
important and when not to worry about it, the argument against polling
in your case is not so much performance as it is that polling is more
complex, more difficult to maintain, requires more code, and is a bit
less efficient. Again, I ask, what's the problem with just using WFSO
for you little "shell" application? There is no need whatsoever for
polling.
=========================
Where the Wait*** APIs fall down is that they are WAIT apis when a
polling loop is capable of more. Its trivially easy to poll and wait
and do something and respond to something else all in one place where
when you WAIT, you WAIT. With a polling loop you can test multiple
things just by adding another test where with WAIT apis you have to
rewrite the call instead to wait on multiple events.
The flexibility issue is this, for trivial code like,
@@:
OS_YIELD_TIMESLICE
perform_key_test_for_user_exit
test_exit_code_of_running_app
refresh_the_window
update_clock_display
test_if_file_exists
send_a_message_to_something
add_anything_else_you_like_here
test_condition_and_loop_back
You can do more or less anything you like with a massive range of
options with very low overhead where high level predefined WAIT APIs
are nothing like as flexible and to compensate for their clunkiness you
have to start a number of other threads and then if you need it you
must them work out a technique to synchronise the extra threads which
buys you higher overhead again and a further increase in complexity.
Write a simple polling loop and you are free of all of this additional
overhead. Being in a single thread you don't have to carry the
additional overhead of multiple threads and there are no
synchronisation issues to increase the overhead either. This is why
polling technology is superior technology because it is adaptable,
flexible, efficient and simple.
The alternatives are clunky, limited in their range, have higher
overhead with additional threads and don't measure any better.
=========================
Yet you are the one constantly whipping up the storm with all these
threads you create all the time. Here, on the Win32ASM board, and even
on the MASMForum board.
=========================
No, I in fact did not start the argument, is has been spat at me for
years on end as the ONLY way a task should be done which is simply
nonsense when the OS is polling based and polling dependent. It is
simpler for me to keep track of it here than all over the place.
Yes, I use both in my ShellMsg library function, it uses
MsgWaitForMultipleObjects in order to continue processing messages in a
GUI or COM application while waiting for a process to end. It works
quite well and uses a "blocking loop" to achieve the results I was
looking for.
> Especially when they are less code and easier to use than the polling
> loop. I keep asking, "What's the aversion to using WFSO?" Thus far,
> Hutch has not answered this question. I hear a nebulous "it's more
> flexible." But that doesn't apply to the current situation. No such
> flexibility is necessary.
> Cheers,
> Randy Hyde
>
I agree, WFSO is much easier to use, is technically better and is
recommended by Microsoft. Pretty much a 3 out of 3 win there, though
Hutch mentions some claptrap about the AMD K6-2 and Win98 from time to
time he has never backed it up with a link to the KB at MSDN so I put
that one in the single-malt induced fantasy file (a round receptacle
beside my desk).
Donkey
>
> Where the Wait*** APIs fall down is that they are WAIT apis when a
> polling loop is capable of more.
So please explain how you are using that "more" in your little shell
application. A pair of pliers is capable of doing so much more than a
box wrench, but that doesn't mean you use a pair of pliers when the
box-end wrench is the more appropriate tool for the job.
> Its trivially easy to poll and wait
> and do something
Granted, but it's even easier to use WFSO here. And shorter. And
faster.
So what's your aversion to WFSO? It *is* the right tool for the job
here.
> and respond to something else all in one place where
> when you WAIT, you WAIT. With a polling loop you can test multiple
> things just by adding another test where with WAIT apis you have to
> rewrite the call instead to wait on multiple events.
You are not testing multiple things. You are waiting only for process
termination.
(oh, and BTW, there is a WaitForMultipleObjects if you *do* need to
wait for multiple things.)
>
> The flexibility issue is this, for trivial code like,
>
> @@:
> OS_YIELD_TIMESLICE
> perform_key_test_for_user_exit
> test_exit_code_of_running_app
> refresh_the_window
> update_clock_display
> test_if_file_exists
> send_a_message_to_something
> add_anything_else_you_like_here
> test_condition_and_loop_back
This is not what the program you're being criticized for does. All
you're saying is "I could use my pair of pliers for some other job, so
they must be the perfect tool for tightening this 12mm nut." The truth
is, the box-end wrench would probably be a *far* wiser choice. Just as
WFSO is the wiser choice for your "shell" code example. As for the code
above, I don't see any *time dependent* code present, so I'm not
convinced that sleeping in this loop is appropriate. I'd strongly
consider using WaitForMultipleObjects if I were you. Sleep should be
used when *time* is an explicit component of what's going on.
>
> You can do more or less anything you like with a massive range of
> options with very low overhead where high level predefined WAIT APIs
> are nothing like as flexible and to compensate for their clunkiness you
> have to start a number of other threads and then if you need it you
> must them work out a technique to synchronise the extra threads which
> buys you higher overhead again and a further increase in complexity.
Actually, it's the polling that gets you into trouble as you begin
adding other threads. APIs like WaitForMultipleObjects were
*explicitly* designed to handle the situation you're discussing. Not,
of course, that this has anything to do with the criticism of your
original project, which simply polls on a single event that could be
more efficiently handled by WFSO.
>
> Write a simple polling loop and you are free of all of this additional
> overhead.
???
What overhead?
It's the polling loop that has the additional overhead.
It's the polling loop that takes more code.
> Being in a single thread you don't have to carry the
> additional overhead of multiple threads and there are no
> synchronisation issues to increase the overhead either. This is why
> polling technology is superior technology because it is adaptable,
> flexible, efficient and simple.
WFSO is more adaptable, more flexible, more efficient, and even
simpler. And it scales well, too.
>
> The alternatives are clunky, limited in their range, have higher
> overhead with additional threads and don't measure any better.
Define "clunky".
I see one procedure call for WFSO. I see a bunch of lines of code for
your polling loop. Based on my understanding of the term "clunky", I
argue that the polling code is the clunky code.
>>
> No, I in fact did not start the argument, is has been spat at me for
> years on end as the ONLY way a task should be done which is simply
> nonsense when the OS is polling based and polling dependent. It is
> simpler for me to keep track of it here than all over the place.
>
Okay, but you spread it like a virus :-)
cheers,
Randy Hyde
=======================================
Granted, but it's even easier to use WFSO here. And shorter. And
faster. So what's your aversion to WFSO? It *is* the right tool for the
job here.
=======================================
This is the assumption that I have taken to task. I don't have any
problem with WaitFor(Whatever)Object([s]Ex) at all but I see it as "A"
tool for the job, not "THE" tool for the job.
Like anyone around, I can type a small polling loop faster than I can
rat through Microsoft tecnical data selecting an appropriate Wait** API
so its not a code production issue. I bothered to write the 1000 thread
test to prove that it is not an efficiency issue either.
While you seem happy enough with the idea that you get nothing for
nothing in computer functionality, many others have flapped their mouth
off about getting something for nothing and there have been enough
posts made claiming absolute ZERO % overhead with Wait*** APIs which is
clearly nonsense.
It is a transfer of functionality to the OS which must poll the
notification indicators for the event(s) that have to be signalled and
when those event(s) are all signalled if that is the option required,
then it re-enables and notifies the caller of the Wait*** API.
Now I have no doubt that this is an efficient technique but then when
you run a test of 1000 threads each containing a polling loop which it
turn starts an instance of an application and the total for each
instance of a thread, polling loop and running instace of an
application is one 200th of one percent, the polling loop component of
each instance is proven as very efficient and with processor usage so
low, the OS technique is not improving on it.
What I use the Sleep API for is a defacto "YieldThisTimeSlice()" as
there is no better solution available at an applicaion level but in
fact the general code design is more flexible than this.
@@:
invoke Sleep,set_your_delay_here
Call your_test_here
check_its_return_value_here
loop_back_if_condition_is_not_met
With a basic design like this that the "shell" procedures use, it
certainly gives nothing away in efficiency terms and this is proven by
testing but it is very easy to add bits to it.
test_for_another_condition
check_its_return_value_here
exit_the_loop_if_condition_is_met
do_something_else_as_well
Now if you have in mind something that has to keep track of an event
that may take a long time to finish, this general style of code starts
to get far more efficient again simply by increasing te delay in
Sleep() to a longer duration. Set it to 1000 MS (1 second) and its
efficiency increase is multiplied by the duration of 1 second divided
by the number of time slices the OS makes in one second.
The advantage of this general technique is that it places its OS polled
demand in one place only, the Sleep API and it places no other overhead
on the OS at all but by bothering to do your own testing in the form
you require, it is both far more efficient and can be exactly tailored
to the task you have in mind. The alternative is to start a seperate
thread for each additional task and if requred, you must also
synchronise each task and the overhead and complexity here makes the
overhead of a single efficient polling loop very attractive.
With the years of persistent criticisms of using a technique that the
entire operating system depends on I have head some absolute stupidity
argued with a maximum of invective, you CAN get something for nothing
by using MAGIC, the OS is always right, even when its wrong, if the OS
uses this technique, rename it to something else and when the technique
is proven as fundamental OS tchnology, go into DENIAL. Then there is
the approach that in the face of proof of efficiency, the MAGIC method
is defined as necessarily TRUE even when it cannot prove that it is
more efficient and that by being necessarily TRUE, it MUST be a netter
technique.
This is why I rely on testing with indifference to the ignorance and
stupidity I have heard for years on end, pay no attention to matters of
fashion and write code that simply works well. Below is the "shock
horror" offending code that does all of the things it is supposed to do
at an efficiency level that its critics cannot improve on.
@@:
invoke GetExitCodeProcess,
pr_info.hProcess,ADDR xc ; get the exit condition
invoke Sleep, 1 ; yield the remaining time slice
cmp xc, STILL_ACTIVE ; test the exit condition
je @B ; exit if its met or try again
Now this truly breaks the rules of fashion but it also kicks ass in
terms of both function and efficiency so the last argument left is
WaitFor(whatever)object(Ex[s]) in that it is less typing. Having coded
in assembler for a long time this is not really a problem,
push 0
push INFINITE
lea eax, pr_info.hProcess
push eax
call WaitForSingleObjectEx
When someone tries to sell me the idea that something is the ONE TRUE
WAY[TM] in a pluralistic world, I am inclined to sell them the idea
that their ONE TRUE WAY[TM] is only a member of a class of MANY OTHER
WAYS[TM] many of which work just as well and are a lot more flexible to
use.
> Okay, but you spread it like a virus :-)
Not really, I just get tired of the stupidity after some years of
listening to invective and associated bullsh*t and put a mechanism in
place to counter the noise.
> It is a transfer of functionality to the OS which must poll the
> notification indicators for the event(s) that have to be signalled and
> when those event(s) are all signalled if that is the option required,
> then it re-enables and notifies the caller of the Wait*** API.
They are not polled. Read my lips (as well as the documentation from
Microsoft Press, disassemblies, traces, etc. whatever) - they are NOT
polled. App is terminated (ExitProcess, TerminateProcess, Exception,
whatever), windows does cleanup, runs through the list of threads
waiting for the process object, and wakes them up (if they don't have
anything else they're waiting on). This is a one-shot low-overhead
action, it is not a repeated polling action.
> What I use the Sleep API for is a defacto "YieldThisTimeSlice()" as
> there is no better solution available at an applicaion level but in
> fact the general code design is more flexible than this.
SwitchToThread() on NT... or one of the WFO variants, where applicable.
Which is pretty damn often, even if you have some polling-style action
to do. Why? Because WFO will wake you up either when the timeout has
happened, or when one (or all) of the objects become signalled. This is
better latency than only waking up at timeout and then checking whether
objects are signalled.
> Now if you have in mind something that has to keep track of an event
> that may take a long time to finish, this general style of code starts
> to get far more efficient again simply by increasing te delay in
> Sleep() to a longer duration. Set it to 1000 MS (1 second) and its
> efficiency increase is multiplied by the duration of 1 second divided
> by the number of time slices the OS makes in one second.
And then you have a 1-second latency before you detect process
termination. WFSO has as low latency as you will get, and still less CPU
usage. It's a win-win situation.
> The advantage of this general technique is that it places its OS polled
> demand in one place only, the Sleep API and it places no other overhead
> on the OS at all but by bothering to do your own testing in the form
> you require, it is both far more efficient and can be exactly tailored
> to the task you have in mind.
The OS doesn't use polling for this kind of thing, sorry.
> The alternative is to start a seperate thread for each additional task
> and if requred, you must also synchronise each task and the overhead
> and complexity here makes the overhead of a single efficient polling
> loop very attractive.
You can wait for up to 64 objects per thread. With zero overhead and
perfect synchronization. Beats polling in terms of simplicity and
overhead (even if the overhead is miniscule, it's there).
=================================
They are not polled. Read my lips (as well as the documentation from
Microsoft Press, disassemblies, traces, etc. whatever) - they are NOT
polled. App is terminated (ExitProcess, TerminateProcess, Exception,
whatever), windows does cleanup, runs through the list of threads
waiting for the process object, and wakes them up (if they don't have
anything else they're waiting on). This is a one-shot low-overhead
action, it is not a repeated polling action.
=================================
No I don't read your lips, I read what you say.
=================================
runs through the list of threads waiting for the process object, and
wakes them up (if they don't have anything else they're waiting on)
=================================
Polling by any other name still checks one thing after another.
SwitchToThread has the same limitations as Sleep() but witout the
option to yield anyway.
================================
If there are no other threads ready to execute, the operating system
does not switch execution to another thread, and the return value is
zero.
================================
And then you have a 1-second latency before you detect process
termination. WFSO has as low latency as you will get, and still less
CPU
usage. It's a win-win situation.
================================
If the process takes a long time, who cares about the latency but with
Sleep() you can adjust that.
> It's a win-win situation
No, its a Wait, Wait situation.
Even bigger smile,
================================
You can wait for up to 64 objects per thread. With zero overhead and
perfect synchronization. Beats polling in terms of simplicity and
overhead (even if the overhead is miniscule, it's there).
================================
Polling of course does not have this limitation but I am hearing te
same waffle again that you get something for nothing where in fact you
only shift the load to the OS which must poll the number of events
waiting to be flagged.
I wonder how long it will take to sink in that you get NOTHING for
NOTHING on a computer.
You keep writing spaghetti slop, the rest of us will do our
best at writing high-performance, highly-reliable software.
The problem isn't so much that Hutch can keep writing his code the way
he wants. He's entitled to write code however badly he chooses. The
problem is that this stuff is going into a library module that other
MASM32 users learn from and *that's* bad. They should be taught the
proper way to do this, not a hack.
Cheers,
Randy Hyde
Having pretty much lost interest in this argument as Hutch will never
admit a mistake in his slop, I have to say that I don't think he really
cares about "demonstrating the right way" or about beginners at all. He
will just continue to pollute ALA with useless threads and insults until
we all give up and in his mind he wins by default. He is wrong, he must
know he's wrong, but that makes little difference as long as he believes
he has won the argument, everyone else be damned. He has even attacked
and attempted to ridicule you, though that goal backfired badly and he
ended up looking like an ass. He has little reputation left to defend
and that is fading fast with this argument, however he will always have
a few sycophants and they will be doomed to rewrites and patches like
shell_ex (or whatever he calls it), another peice of slop code.
Donkey
I agree. Best to move on now.
Cheers,
Randy Hyde
You need to dilute your ignorance here.
====================
I never liked the term "polling loop", I prefer a more explicit term. I
beleive that the "polling loop" that Hutch posted (shell) and the
GetMessage loop are equivalent in the following sense; both loops are
Spin-Wait loops,
====================
The term redefinition does not work for you here. A spinlock is a
synchronisation method at an OS level. If you bother to take a look at
either polling loop you will see that they loop once then perform the
next action. With GetMessage() it polls for the next available message
if its available, with the "shell" algo it yields to the OS and does
not return for at least one processor time slice or longer.
====================
One waits for a specific unchanging interval to expire (Sleep(1))
====================
A timeslice is longer than 1 millisecond and unles you set the minimum
time delay to a value in excess of what your particular OS is running,
it functions as a yield to the OS, that is why it tests at such an
efficient level of processor usage.
====================
Other than that deceptively small difference, there is no real logical
divergence. However that difference is at the root of all of the
threads that Hutch has seen fit to infect this newsgroup and others
with.
====================
The only deception here is the assertion you have made on the basis of
what you don't understand, yielding unused time to the OS is a good
thing{TM] and that is why a correctly written polling loop is so
efficient.
====================
Almost any programmer can see the advantage to waiting on an event
rather than continually asking if it has happened yet, I cannot see the
validity in any argument to the contrary.
====================
An operating system is not a magic black box and any task you delegate
to the OS still must be performed by the OS. Getting something for
nothing is a pipe dream on a computer, understand this and you will
know what your costs are and write more efficient code.