PowerBASIC Forums
  Programming
  XP vs 95/98 - threads - slow, slow, slow ??? (Page 1)

Post New Topic  Post A Reply
profile | register | preferences | faq | search

UBBFriend: Email This Page to Someone!
This topic is 2 pages long:   1  2 
next newest topic | next oldest topic
Author Topic:   XP vs 95/98 - threads - slow, slow, slow ???
Chris Boss
Member
posted March 04, 2004 09:29 AM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
I just came across something that I find very strange.

I wrote a simple program on Windows 95 that has two threads, which
calculate coordinates in the threads, sends a message to the main
GUI thread to draw the images.

On my Windows 95 system the program runs quite fast. This PC is
a Pentium 166 mhz (32 meg ram). I then ran the program on a
Windows ME system (Pentium 667 mhz, 256 meg ram) and it runs
much, much faster.

I recently purchased a new computer which has Windows XP
(Pentium 2.5 ghz, 256 meg ram) which should be 16 times faster
than my Win95 system and 4 times faster than my WinME system.

Amazingly, this program I wrote runs slower on my XP system than
it does on my Win95 system (which should be 16 times slower) !!!

Why is this ?

Why would a program run slower on a Pentium 2.5 ghz machine than
it does on a Pentium 166 mhz ?

I know XP has lots of services running, but I deactivated about
half of them that were not needed, yet the system is still very
slow when running this program.


------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

IP: Logged

Kev Peel
Member
posted March 04, 2004 09:36 AM     Click Here to See the Profile for Kev Peel     Edit/Delete Message   Reply w/Quote
One thing I have noticed with XP is that it doesn't crash (the OS itself) - it just 'slows down' after a lot of program GPFs. Does a reboot solve the problem? Have you checked for memory corruption in the program and run it through the debugger also?

------------------
Kev Peel
http://www.kgpsoftware.com

IP: Logged

Chris Boss
Member
posted March 04, 2004 10:05 AM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
I ran another test using another program that simply draws an
image and then using the ScrollWindow API function scrolls the
image diagonally.

The Win95 (Pentium 166 mhz) system scrolled at 72 frames per second.

The XP (Pentium 2.5 ghz) system scrolled at 2580 frames per second.

As expected, the XP system was 35 times faster.

This would seem to imply that the problem with the first program
is the use of threads. Does XP handle threads differently than
Win95 ?

Has anyone experienced problems with slow thread speed on XP ?

To Kev,

The program in the test above is very sound and it is not GPF'ing.
The images are drawn on an EZGUI 3.0 Canvas control which uses
double buffers.


------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

IP: Logged

Chris Boss
Member
posted March 04, 2004 10:09 AM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
Here is the code to the EZGUI 3.0 application that is slower on
XP than Win95:

Maybe there is something in my thread code that XP doesn't like.


#COMPILE EXE
#DIM ALL
' --------------------
#INCLUDE "..\includes\ezgui30.inc"
' --------------------
' *************************************************************************************
' Application Constants and Declares
' *************************************************************************************
DECLARE SUB DForm_Display(BYVAL Parent$)
DECLARE SUB DForm_Design()
DECLARE SUB DForm_Events(CID&, CMsg&, CVal&, Cancel&)
' -------------------------------
%DForm_Thread1_ID = 10
' -------------------------------
DECLARE FUNCTION DForm_Thread1(BYVAL hDlg AS LONG) AS LONG
DECLARE SUB DForm_Thread1_Do_GUI(CVal&)
DECLARE SUB Start_DForm_Thread1()
DECLARE SUB Pause_DForm_Thread1()
DECLARE SUB Resume_DForm_Thread1()
DECLARE SUB Close_DForm_Thread1()
' -------------------------------
%DForm_Thread2_ID = 11
' -------------------------------
DECLARE FUNCTION DForm_Thread2(BYVAL hDlg AS LONG) AS LONG
DECLARE SUB DForm_Thread2_Do_GUI(CVal&)
DECLARE SUB Start_DForm_Thread2()
DECLARE SUB Pause_DForm_Thread2()
DECLARE SUB Resume_DForm_Thread2()
DECLARE SUB Close_DForm_Thread2()

%DFORM_CANVAS1 = 100
%DFORM_CANVAS2 = 105
%DFORM_DBUTTON = 110
' ------------------------------------------------

DECLARE SUB DFORM_DBUTTON_Click()

' *************************************************************************************
' Application Global Variables and Types
' *************************************************************************************
GLOBAL End_DForm_Thread1&
GLOBAL hDForm_Thread1&
GLOBAL End_DForm_Thread2&
GLOBAL hDForm_Thread2&

' --------------------
#INCLUDE "..\includes\ezwmain.inc"
' --------------------

' *************************************************************************************
' EZGUI Program Control Functions
' *************************************************************************************

SUB EZ_Main(VerNum&)
RANDOMIZE
DForm_Display ""
END SUB

' -------------------------------------------------------------------------------------

SUB EZ_DesignWindow(FormName$)
SELECT CASE FormName$
CASE "DFORM"
DForm_Design
CASE ELSE
END SELECT
END SUB

' -------------------------------------------------------------------------------------

SUB EZ_Events(FormName$, CID&, CMsg&, CVal&, Cancel&)
SELECT CASE FormName$
CASE "DFORM"
DForm_Events CID&, CMsg&, CVal&, Cancel&
CASE ELSE
END SELECT
END SUB

' -------------------------------------------------------------------------------------

SUB DForm_Display(BYVAL Parent$)
EZ_Color 0, 17
EZ_Form "DFORM", Parent$, "Drawing on Canvas controls using Threads", 0, 0, 67, 20, "C"
END SUB
' ------------------------------------------------

GLOBAL DForm_FF&

SUB DForm_Design()
LOCAL FF&
'---------------------------------------------------------------
FF& = 9 ' - Offset for Font Numbers
DForm_FF& = FF& ' Global for ODButtons Draw code
'---------------------------------------------------------------
EZ_Color 0, 0
EZ_DefFont FF&+1, "Arial", 14, "V"
EZ_Canvas %DFORM_CANVAS1, 1, 1, 32, 15, "S"
' --------------------------------------------------------------
EZ_Canvas %DFORM_CANVAS2, 34, 1, 32, 15, "S"
' --------------------------------------------------------------
EZ_Color 0, 17
EZ_UseFont FF&+1
EZ_ODButton %DFORM_DBUTTON, 44, 17, 22, 2, "Pause", "T"
' --------------------------------------------------------------
EZ_PostEvent "DFORM", %EZ_Window, 1 ' Initialize Threads or Timer
END SUB
' ------------------------------------------------

SUB DForm_Events(CID&, CMsg&, CVal&, Cancel&)
SELECT CASE CID&
CASE %DForm_Thread1_ID
IF CMsg&=%EZ_Thread THEN
DForm_Thread1_Do_GUI CVal&
END IF
CASE %DForm_Thread2_ID
IF CMsg&=%EZ_Thread THEN
DForm_Thread2_Do_GUI CVal&
END IF
CASE %EZ_Window
IF CMsg&=%EZ_Post THEN ' Form Started - Start Threads or Timer
IF CVal&=1 THEN
Start_DForm_Thread1
Start_DForm_Thread2
END IF
END IF
IF CMsg&=%EZ_Close THEN
Resume_DForm_Thread1
Resume_DForm_Thread2
Close_DForm_Thread1
Close_DForm_Thread2
END IF
CASE %DFORM_DBUTTON
IF CMsg&=%EZ_Click THEN
DFORM_DBUTTON_Click
END IF
IF CMsg&=%EZ_OwnerDraw THEN
EZ_Draw3DButton "DForm", %DFORM_DBUTTON, CVal&, 17, 0, DForm_FF& + 1
END IF
CASE ELSE
END SELECT
END SUB
' ------------------------------------------------

SUB Start_DForm_Thread1()
THREAD CREATE DForm_Thread1(EZ_Handle("DForm",0)) TO hDForm_Thread1&
END SUB

' -------------------------------

SUB Pause_DForm_Thread1()
LOCAL RV&
THREAD SUSPEND hDForm_Thread1& TO RV&
END SUB

' -------------------------------

SUB Resume_DForm_Thread1()
LOCAL RV&
THREAD RESUME hDForm_Thread1& TO RV&
END SUB

' -------------------------------

TYPE TDraw1
CW AS LONG
CH AS LONG
BGFlag AS LONG
X1 AS LONG
Y1 AS LONG
X2 AS LONG
Y2 AS LONG
CL AS LONG
END TYPE

FUNCTION DForm_Thread1(BYVAL hDlg AS LONG) AS LONG
LOCAL RV&, W&, H&, EW&, EH&, SFlag&, ToggleFlag&, C&
LOCAL TD AS TDraw1, SlideX&, SlideY&, CT&, SlideCT&, SlideD&
EZ_GetCanvasSize "DForm", %DFORM_CANVAS1, W&, H&
TD.CW=W&
TD.CH=H&
GOSUB InitData1
C&=10
SlideD&=1
DO
IF End_DForm_Thread1&=0 THEN
SLEEP 1
IF ToggleFlag&=0 THEN ToggleFlag&=1 ELSE ToggleFlag&=0
SFlag&=0
TD.BGFlag=0
CT&=CT&+1
IF CT&=SlideCT& THEN
SlideCT&=SlideCT&+1
IF SlideD&=0 THEN
SlideX&=-SlideX&
SlideD&=1
ELSE
SlideY&=-SlideY&
SlideD&=0
END IF
CT&=0
END IF
TD.X1=TD.X1+SlideX&
IF TD.X1<0 THEN TD.X1=0
IF TD.X1>=W& THEN SFlag&=1
TD.Y1=TD.Y1+SlideY&
IF TD.Y1<0 THEN TD.Y1=0
IF TD.Y1>=H& THEN SFlag&=1
TD.X2=TD.X1+EW&-1
IF TD.X2<0 OR TD.X2>=W& THEN SFlag&=1
TD.Y2=TD.Y1+EH&-1
IF TD.Y2<0 OR TD.Y2>=H& THEN SFlag&=1
IF SFlag& THEN
GOSUB InitData1
TD.BGFlag&=1
TD.CL=TD.CL+1
C&=C&+1
IF C&=23 THEN C&=10
END IF
IF ToggleFlag& THEN
TD.CL=C&+8
ELSE
TD.CL=C&
END IF
RV& = EZ_SendThreadEvent(hDlg, %DForm_Thread1_ID, VARPTR(TD))
ELSE
EXIT DO
END IF
LOOP
FUNCTION=1
EXIT FUNCTION

InitData1:
TD.X1=(W&/2)-(W&/16)
TD.Y1=(H&/2)-(H&/16)
EW&=W&/16
EH&=H&/16
TD.X2=TD.X1+EW&
TD.Y2=TD.Y1+EH&
SlideX&=RND(2,5)
SlideY&=RND(2,5)
CT&=0
SlideCT&=RND(3,5)
RETURN

END FUNCTION

' -------------------------------

SUB Close_DForm_Thread1()
LOCAL EFlag&, N&
End_DForm_Thread1& = 1
N&=0
DO
SLEEP 5
EZ_DoEvents 255
EFlag&=0
THREAD STATUS hDForm_Thread1& TO EFlag&
INCR N&
IF N&>5000 THEN EXIT DO
IF EFlag&<>&H103 THEN EXIT DO
LOOP
THREAD CLOSE hDForm_Thread1& TO N&
END SUB

' -------------------------------

SUB DForm_Thread1_Do_GUI(CVal&)
LOCAL TD AS TDraw1 PTR
LOCAL AFG&, ABG&, AFnt&, CW&, CH&
AFG&=EZ_FG
ABG&=EZ_BG
AFnt&=EZ_Font
TD=CVal&
CW&=@TD.CW
CH&=@TD.CH
EZ_StartDraw "DForm", %DFORM_CANVAS1, CW&, CH&, ""
IF @TD.BGFlag<>0 THEN
EZ_Clear "DForm", %DFORM_CANVAS1
EZ_CShowRect 0,0, CW&-1, CH&-1
END IF
EZ_Color @TD.CL, 0
EZ_CDraw %EZ_Ellipse, @TD.X1, @TD.Y1, @TD.X2, @TD.Y2, 1,0
EZ_CShowRect @TD.X1, @TD.Y1, @TD.X2, @TD.Y2
EZ_EndDraw
EZ_Color AFG&, ABG&
EZ_UseFont AFnt&
END SUB

' -------------------------------

SUB Start_DForm_Thread2()
THREAD CREATE DForm_Thread2(EZ_Handle("DForm",0)) TO hDForm_Thread2&
END SUB

' -------------------------------

SUB Pause_DForm_Thread2()
LOCAL RV&
THREAD SUSPEND hDForm_Thread2& TO RV&
END SUB

' -------------------------------

SUB Resume_DForm_Thread2()
LOCAL RV&
THREAD RESUME hDForm_Thread2& TO RV&
END SUB

' -------------------------------

TYPE TDraw2
CW AS LONG
CH AS LONG
CV AS LONG
CL AS LONG
END TYPE

FUNCTION DForm_Thread2(BYVAL hDlg AS LONG) AS LONG
LOCAL RV&, TD AS TDraw2, W&, H&
EZ_GetCanvasSize "DForm", %DFORM_CANVAS1, W&, H&
TD.CW=W&
TD.CH=H&
TD.CL=2
W&=W&-(W&/4)
DO
IF End_DForm_Thread2&=0 THEN
SLEEP 5
TD.CL=TD.CL+1
IF TD.CL=15 THEN TD.CL=2
TD.CV=INT(RND(5,W&))
RV& = EZ_SendThreadEvent(hDlg, %DForm_Thread2_ID, VARPTR(TD))
ELSE
EXIT DO
END IF
LOOP
FUNCTION=1
END FUNCTION

' -------------------------------

SUB Close_DForm_Thread2()
LOCAL EFlag&, N&
End_DForm_Thread2& = 1
N&=0
DO
SLEEP 10
EZ_DoEvents 255
EFlag&=0
THREAD STATUS hDForm_Thread2& TO EFlag&
INCR N&
IF N&>5000 THEN EXIT DO
IF EFlag&<>&H103 THEN EXIT DO
LOOP
THREAD CLOSE hDForm_Thread2& TO N&
END SUB

' -------------------------------

SUB DForm_Thread2_Do_GUI(CVal&)
LOCAL TD AS TDraw2 PTR
LOCAL AFG&, ABG&, AFnt&, CW&, CH&, BW&
AFG&=EZ_FG
ABG&=EZ_BG
AFnt&=EZ_Font
TD=CVal&
CW&=@TD.CW
CH&=@TD.CH
BW&=4
EZ_StartDraw "DForm", %DFORM_CANVAS2, CW&, CH&, ""
EZ_CScroll 0, 0, CW&-1, CH&-1, 0, -BW&
EZ_Color 0,0
EZ_CDraw %EZ_Fill, 0, CH&-BW&-1, CW&-1, CH&-1, 1,1
EZ_Color 1,@TD.CL
EZ_CDraw %EZ_Rect, CW&-@TD.CV-1, CH&-BW&, CW&-1, CH&-1, 1,1
EZ_EndDraw
EZ_Color AFG&, ABG&
EZ_UseFont AFnt&
END SUB

' ------------------------------------------------

SUB DFORM_DBUTTON_Click()
STATIC TFlag&
IF TFlag&=0 THEN
Pause_DForm_Thread1
Pause_DForm_Thread2
TFlag&=1
EZ_SetText "DForm", %DFORM_DBUTTON, "Resume"
ELSE
Resume_DForm_Thread1
Resume_DForm_Thread2
TFlag&=0
EZ_SetText "DForm", %DFORM_DBUTTON, "Pause"
END IF
END SUB


------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

IP: Logged

Patrice Terrier
Member
posted March 04, 2004 10:21 AM     Click Here to See the Profile for Patrice Terrier     Edit/Delete Message   Reply w/Quote
Chris

I am using several threads in my multimedia applications and they run much faster
and more smoothly on XP than on pseudo 32-bit OS (98/ME).

However when I have to deal with a lot of graphics I avoid to create/delete multiple
private DC in memory and try to create only once and use the same DC again and again
as much as I can this speeds up things a lot in my case.

Perhaps you should check this when you use your double buffers.

Something else, what does your EZ_DoEvents do?


------------------
Patrice Terrier
pterrier@zapsolution.com
http://www.zapsolution.com
Toolkit: WinLIFT (Skin Engine), GDI+ helper (Graphic package), dvBTree (Index manager)
Freeware: ZAP Audio Player, ZAP Picture Browser.
Artwork on demand.

[This message has been edited by Patrice Terrier (edited March 04, 2004).]

IP: Logged

Chris Boss
Member
posted March 04, 2004 10:23 AM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
Well, I found the solution to my problem !!!

It turns out XP didn't like the use of the SLEEP command
used in the thread code.

In one thread I used SLEEP 5 and the other SLEEP 1 .

I removed the sleep commands and ran the program again on XP and it
is now lightning fast (definitely 10 to 20 times faster than my
Win95 system).

------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

IP: Logged

Chris Boss
Member
posted March 04, 2004 10:30 AM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
Patrice,

The EZGUI 3.0 Canvas control creates its memory DC's and Bitmaps
only once when the control is created (or resized) and so it
doesn't need to recreate them for every frame. The DC and bitmap
handles are stored by the control and simply used when needed.
When the control is destroyed, the DC's and Bitmaps are then
deleted.

------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

IP: Logged

Michael Mattias
Member
posted March 04, 2004 10:33 AM     Click Here to See the Profile for Michael Mattias     Edit/Delete Message   Reply w/Quote
Another problem might be.. although this seems hidden somewhere in the code which accesses the third-party library...

You say,

quote:

.. sends a message to the main GUI thread to draw the images.

If the third-party library is, in fact, SENDing the message versus POSTing the message, this application is forcing thread switches instead of letting Windows handle it. Not to mention, if all the code is doing is drawing pictures, there's no reason that has to happen "right now" and can't wait for the next 'normal' CPU time slice for the GUI thread.

Without analyzing the source code of the third-party library as used within the context of the specific application, of course, this analysis may be totally moot.

But at least moot is free.

MCM

IP: Logged

Chris Boss
Member
posted March 04, 2004 10:55 AM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
Michael,

You are correct !

EZGUI does force a context switch and this is on purpose.

Posting to the main GUI thread requesting it to update an image
will cause problems because windows can actually get behind in
sending the messages (they stack up).

EZGUI 3.0 sends a message from the secondary threads to the main
GUI thread, since all windows are created in main GUI thread. The
main GUI thread must do the drawing.

When EZGUI 3.0 sends a message from a thread to the main GUI thread
(%EZ_Thread event) it uses critical sections to make sure the main GUI
thread only processes one message at a time.

By using critical sections and sendmessage EZGUI over comes any
problems with being thread safe, otherwise I would have had to
do a complete rewrite of the tool to try to make each function
call thread safe.

In EZGUI apps, the threads are never used for any GUI functionality.
They must send a message to the main GUI thread and request it to
modify the GUI. Because critical sections are used, the main GUI
thread is never doing more than one thing at a time.

I read extensively about using threads before adding thread features
to EZGUI 3.0 and from what I read the recommendation was that
only the main GUI thread should modify the GUI and not the
worker threads. I followed this recommendation.

EZGUI 3.0's thread features are very sound.

As you can see from my posts above, I found the source of the
problem to be the SLEEP command when used in a thread procedure.

I am now getting a couple hundred frames per second on my XP system now,
with this test program.

------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

IP: Logged

Kev Peel
Member
posted March 04, 2004 10:58 AM     Click Here to See the Profile for Kev Peel     Edit/Delete Message   Reply w/Quote
quote:

The program in the test above is very sound and it is not GPF'ing.
The images are drawn on an EZGUI 3.0 Canvas control which uses
double buffers

Chris I was not inferring your code is buggy, I meant other programs that have been run (such as experimental\test code) since system startup

I think Michael has a valid point about 'forcing' GDI messages through.

------------------
Kev Peel
http://www.kgpsoftware.com

IP: Logged

Chris Boss
Member
posted March 04, 2004 11:15 AM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
I have experimented with posting messages from a secondary thread to
the main GUI thread and I found it unreliable on slower systems.

You can get a backlog of messages which build up and the system
can crash.

EZGUI 3.0 forces a context switch on purpose and it actually works
very well.

Context switchs are not a bad thing. They just need to be controlled.

A secondary thread should not attempt to modify any GUI elements
created by another thread. If the controls are created in the
main GUI thread, they must be modified by that main thread.

The problem with accessing a window outside of the thread it
was created in, is that one may not realize that any number of
GDI calls may force a context switch. If you attempt to modify
the window from a another thread, ones code may cause multiple
context switches without you realizing it.

EZGUI handles this by forcing a context switch to the main GUI
thread when the GUI needs to be updated. The worker thread is only
for calculations. EZGUI allows you to pass a pointer in its
%EZ_Thread event so you can pass a block of memory (ie. a TYPE structure)
with data calculated by the worker thread. The worker thread does
as much calculating as possible and then request the main GUI
thread to use that data and update the GUI. Only one planned
context switch will occur using this method. Once the main GUI thread
is in control, any GDI calls made by it are for windows created
by that thread, so no more context switches will occur during the
draw operation.

Also problems can result when more than one thread accesses GDI
objects (bitmaps, DC's, etc.). EZGUI uses critical sections when
the worker thread calls the main GUI thread, so no such problems
occur.

The thread code in EZGUI 3.0 was extremely well thought out and
it works flawlessly.

I just didn't anticipate the problem with using the SLEEP command
(which the EZGUI engine doesn't use, but was just in the app code).

The fact that a slow Win95 system runs the code faster than a
fast XP system obviously indicates that Windows XP handles
the SLEEP call differently. By removing the SLEEP calls, the
EZGUI application was extremely fast on my XP system.

------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

[This message has been edited by Chris Boss (edited March 04, 2004).]

IP: Logged

Michael Mattias
Member
posted March 06, 2004 09:30 AM     Click Here to See the Profile for Michael Mattias     Edit/Delete Message   Reply w/Quote
I was intrigued by this discussion and was looking for info on "overflowing the message queue."

I found in PSDK that NT/XP has a limit of 10,000 messages.. but could not find any limits for Win 9x/ME, nor could I find any good suggestions for querying the current "queued message count" and/or cleaning out the queue by handling the message (I guess I could "switchtothread" to force that to happen, but now all threads of application must cooperate and that seems kind of clunky).

Any ideas?


MCM

IP: Logged

Dominic Mitchell
Member
posted March 06, 2004 12:50 PM     Click Here to See the Profile for Dominic Mitchell     Edit/Delete Message   Reply w/Quote
You can clean out the message queue by using PeekMessage() with the PM_REMOVE flag.
For example, let's say the user is moving an object across the screen with the
keyboard. You will usually end up with a backlog of keyboard messages in the
PostMessage queue when the user releases the key. This results in the object
overshooting the intended destination. This is easily solved by doing the following

' This prevents the controls from over shooting due to keyboard messages piling up
IF ISTRUE PeekMessage(tmsg, hWnd, %WM_KEYUP, %WM_KEYUP, %PM_NOREMOVE) THEN
fwpRemKeys:
IF ISTRUE PeekMessage(tmsg, hWnd, %WM_KEYDOWN, %WM_KEYDOWN, %PM_REMOVE) THEN
GOTO fwpRemKeys
END IF
END IF

The first call to PeekMessage() can be replaced with GetQueueStatus() so in theory
using GetQueueStatus() together with PeekMessage() can be used to empty the posted
message queue of most messages.

------------------
Dominic Mitchell

IP: Logged

Chris Boss
Member
posted March 06, 2004 03:15 PM     Click Here to See the Profile for Chris Boss     Edit/Delete Message   Reply w/Quote
Comment about message backlog:

When I was developing EZGUI 3.0 I ran tests to find the best way
to communicate between a thread and the main GUI thread (the
original thread created by the process).

I tried posting a message which would eventually generate WM_PAINT
messages (the GUI changed and needed to be redrawn) and I found that
I got a backlog of WM_PAINT messages to the point where it would
crash the app and even windows. Because the thread could keep
generating messages at too fast a pace, the main GUI thread could
not keep up with it.

I then tried a method of using SendMessage to generate the GUI
update. By using critical sections, only one message would be
handled by the main GUI thread at a time, and by using sendmessage
I forced a context switch so the main GUI thread was active and
it had time to update itself (process WM_PAINT). The worker
threads never ran faster than the main GUI thread and I didn't
get a backlog of messages.

Posting messages from a thread can be very tricky since you have
no way to syncronize the threads with the main GUI thread. Also
you can't easily pass data pointers, since by time the main GUI
thread processes the message, the data may not exist any more.

Now EZGUI 3.0 does have the ability to post messages from a thread
to the main GUI thread using the EZ_PostThreadEvent command. EZGUI
will track how many pending posted messages there are. in the thread
one can test to see how many pending posted messages there are
using the EZ_GetPostThreadCount function. This is critical so
that the thread can track how many pending messages there are
and then know whether it should slow itself down and post less
messages (or simply wait). The main GUI thread can read the
posted messages and retrieve a string passed by using the
EZ_GetPostThreadStr function. EZGUI creates a new global memory
block for every posted thread message and frees the global
memory block after the main GUI thread processes it. Even the
thread message posting engine uses critical sections to make sure
two threads don't modify the message pool at the same time.

Unless you can track the pending message count, posting messages
from a thread to the main GUI thread can be dangerous.

EZGUI 3.0 supports both techniques, sending a message (which is
the safest and best for most instances) and posting which is
very controlled and requires the thread to test for the pending
message count before posting a new message.

When EZGUI 3.0 sends or posts a message from a thread it generates
an event which is processed by the main GUI event code (no
window procedure messages are processed because EZGUI doesn't use
window procedures or dialog procedures normally, since it is
event based).

I believe EZGUI 3.0's methods of communicating between a thread
and the main GUI thread are as safe as it can get. A lot of testing
(and research) went into designing the engine.

Just to make sure the programmer writes the thread code correctly,
the Visual Designer has the ability to generate all the necessary
thread code for you. The designer can generate the code for up
to two threads per Form and it generates the thread creation code,
thread pause code, thread resume code and the thread termination
code. I wanted to make sure thread code was written correctly,
especially the thread termination code which can be a bit tricky.

Threads are great, but they can also be dangerous if not used
correctly.

I would be interested to find out why Windows XP is more
sensitive to the Sleep command in PB (which calls the Sleep API function).
My Win95 system didn't slow down because I used sleep, but XP
slowed down significantly. Maybe because XP is based on NT and it
has services. It is amazing how many services are running on an
XP system by default. I turned a bunch off and still had a good twenty
or more services running (you can't turn them all off). Initially
there was 30 or 40 services running. Even with a 2.5 ghz computer
thats a lot of CPU time in running all those services.


------------------
Chris Boss
Computer Workshop
Developer of "EZGUI"
http://ezgui.com

[This message has been edited by Chris Boss (edited March 06, 2004).]

IP: Logged

Dominic Mitchell
Member
posted March 06, 2004 07:08 PM     Click Here to See the Profile for Dominic Mitchell     Edit/Delete Message   Reply w/Quote
Chris,

There are some misconceptions in your post. Don't get me wrong, I use
SendMessage to synchronize threads a lot. It's easy to implement and
effective. However, your statement that PostMessage is dangerous defies
conventional wisdom. Every author I have read on the subject strongly
recommended the use of PostMessage over SendMessage to communicate between
threads because in the case of SendMessage if the receiving thread hangs,
the sender is toast. SendMessageTimeout is a better choice if you must
use SendMessage (this piece of advice I rarely follow myself).

The problem you were seeing could not have been the result of a backlog of
WM_PAINT messages because there are no WM_PAINT messages in the queue per se.
It would have been caused by a backlog of the messages you were posting to
generate the WM_PAINT messages. When a portion of any window created by a
thread becomes invalid, the QS_PAINT wake flag for the thread is turned on.
GetMessage/PeekMessage will synthesize a WM_PAINT message for the proper
window when this flag is on. The flag is turned off only when all windows
created by a thread have been validated.

------------------
Dominic Mitchell

IP: Logged


This topic is 2 pages long:   1  2 

All times are EasternTime (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply
Hop to:

Contact Us | PowerBASIC BASIC Compilers

Copyright © 1999-2005 PowerBASIC, Inc. All Rights Reserved.


Ultimate Bulletin Board 5.45c