I'm working on a project that involve multithreading processes
I've been experimenting with the CreateThread() Win32 Api function,
and I've noticed that It looks like there is a limitation
in the number of thread you can create : Here is the code I'm playing
with :
METHOD M_Api() CLASS StandardShellWindow
LOCAL hThread AS PTR
LOCAL nID AS DWORD
LOCAL n AS DWORD
FOR n := 1 UPTO 20
SELF:nInstance += 1 // Declared as a dword in StandardShellWindow
class
_DebOut32(PSZ( NTrim(SELF:nInstance) )) // Print in DebugView
hThread := CreateThread( NULL_PTR, 0, @W32ThreadFunction(), 0,
n,@nID )
NEXT
STATIC FUNCTION W32ThreadFunction( ) AS DWORD PASCAL
GetAppObject():Exec()
RETURN 0
Now, the above statement is working for about 60 times, but for 61st
instance Windows (2000 sp2) raise an application error with the
following details :
The instruction at "0x1004f1d1" referenced memory at "0x00000002", the
memory could not be "written"....
I did not manage to catch the error with VO, even with a BEGIN/END
SEQUENCE statement
What am I doing wrong here ? Please help !
I've tried on different machine (still running W2K) and I get exactly
the same message
Oh by the way, I heard Ginny has been writing a paper on
multithreading, Does anyone knows where I can pick it up ?
Merry Christmas to all of you and happy new VO year !
Nico
I cannot help you except by adding my problem to yours.
I'm using CreateVOThread(). No data is passed to the threaded function
which has one simple, solitary line - FCOPY("a.dbf", "b.dbf").
Whether I use ExitVOThread() or simply return from this function;
whether I keep the ptr returned by CreateVOThread or discard it, the
app slows and runs out of dynamic memory after 3 iterations. If I call
my function directly, I have no problems.
I feel I may be missing something glaringly simple! Anyone care to
sort Nico and me out. As Nico says, it is the season of goodwill, and
I extend this to all of you - so please put me out of my misery
without too much sarcasm <g>.
Dave Francis
I do not save the ni...@microsurveys.co.uk (nico) wrote in message news:<fde4aab8.01121...@posting.google.com>...
Hope this helpful and can sort your problem out.
Nico
PS : Still can't work out what is wrong with using
"GetAppObject():Exec()" in the thread funtion, snniff...
Thanks for finding Ginny's paper, and thanks to Ginny for sharing her
wisdom and telling me to use CloseHandle(). My problem's solved! Nico,
shouldn't you be using CreateVOThread() - not CreateThread()?
Dave Francis
ni...@microsurveys.co.uk (nico) wrote in message news:<fde4aab8.0112...@posting.google.com>...
See my earlier posting - I do use semaphores to stop the threads
overlapping, and the full thread does a lot of processing on file "a"
before copying it. Anyway, I'm home and dry on my problem so let's see
what's giving you grief.
Are you sure the problem is in the thread, or is it the launching
function that is giving you problems? I never like code like
...(PSZ(... If you expand this line and allocate locals for each
step, does that make any difference?
And as my mother used to say, "please don't sniff - use your
hankerchief" <g>
Dave Francis
ni...@microsurveys.co.uk (nico) wrote in message news:<fde4aab8.01121...@posting.google.com>...
> See my earlier posting - I do use semaphores to stop the threads
Sorry, I didn't see that...
> Are you sure the problem is in the thread, or is it the launching
> function that is giving you problems? I never like code like
> ...(PSZ(... If you expand this line and allocate locals for each
> step, does that make any difference?
The problem is definitely in the thread function . Indeed, if I do
something else that GetAppObject():Exec(), the app works like a
charm.
Now the PSZ() thing, is just there for debug purposes and if I remove
it, that does not make any differences….
I am now looking in the VO SDK to find out if I can see where things
are going wrong. I'm also looking in the Black Voodoo Web Server
(thanks Geoff for reminding me that ), as I'm doing a TCP server as
well.
So there is still some hope !
Nico
Try CreateVOThread with the same parameters instead of CreateThread. I don't
know if this will solve your problem, but I am interested in what you find out.
Meinhard has a VO class for multithreading as does Fabrice Foray, so you might
get some ideas from their work.
Ginny
"nico" <ni...@microsurveys.co.uk> wrote in message
news:fde4aab8.01121...@posting.google.com...
The next thing I'd suggest is not using VO functions like FCopy to copy the
file. Try WinAPI functions CreateFile, ReadFile, WriteFile and CloseHandle
instead. This keeps VO's dynamic memory system out of the way. I don't know what
the code to FCopy looks like, but there could be a problem in there with
multiple threads.
Ginny
"Dave Francis" <da...@suilven.com> wrote in message
news:8b6e85b9.01121...@posting.google.com...
I'll take your advice. As I understand the problem, dynamic memory can
be used within any thread ok, but sharing variables between threads is
a no-no. Have I got this right?
Dave Francis
"Ginny Caughey" <ginny....@wasteworks.com> wrote in message news:<9vr469$efr$1...@suaar1aa.prod.compuserve.com>...
> Meinhard has a VO class for multithreading as does Fabrice Foray, so you might
> get some ideas from their work.
I've looked at Fabrice's work, but the I've also looked at the
MultiThreadedStandard sample (from the sample gallery), and this is
why
I'm trying to do this GetAppObject():Exec() within the thread
function, like they do it.
The above statement is great to keep the thread alive and use Dispatch
mechanism
I've also tried with the suggestions from your paper, ( CloseHandle()
etc... ),
but again Windows does like it
Just one more precision, I'm not expecting to be able to create
thousand of threads like that, but I thought that Windows could handle
at least a few hundreds...
Nico
You can use dynamic memory within a worker thread, but the GC still needs time
to kick in so you might have to have some
Sleep()s in your loops so everybody gets time slices. The Windows 2000 (and XP)
algorithm for giving time slices to starved threads comes out about once every 3
seconds (NT and the other Microsoft OSes don't even try to help starved
threads). This might not be enough to keep dynamic memory working well. And as a
general rule, reading and writing files (as opposed to using an RDD to read
field data) doesn't really require the overhead of dynamic memory, so I find
it's best as a general rule to simply avoid it - even if I'm not multithreading.
It saves a lot of 5333s. <g>
As for sharing variables between threads, you can to that too if you're careful
to use critical sections so only one thread gets to update a shared variable at
a time (and possibly triggering GC activity). Usually this imposes a performance
hit you don't want because other threads are blocking, so other approaches might
be better.
Ginny
"Dave Francis" <da...@suilven.com> wrote in message
news:8b6e85b9.01122...@posting.google.com...
First I would suggest avoiding the MultiThreadedStandard app from the samples
gallery. The Black Voodoo WWW server example is a better one since it doesn't
try to do GUI things in worker threads.
Windows threading does work fine - I've got multiple threads running in
production apps all over the US and Canada with no problems - but you have to be
careful. I suspect your coding isn't paranoid enough. <g> You have to be really,
really careful and sometimes there's an element of trial and error involving
thread priorities, Sleep()s, etc.
Ginny
"nico" <ni...@microsurveys.co.uk> wrote in message
news:fde4aab8.01122...@posting.google.com...
That's right Black Voodoo is a good example. Indeed I'm trying to get
the
same kind of TCP server architecture, but in a more object oriented
way, I would say... I explain : I have been inspired by FabWinsock for
the network side of things, and it's much easier to understand it. Now
the problem is
that indeed there is a need for a GUI object to receive the messages,
even if nothing has to be shown.
Anyway, I've drilled down in the VO SDK to find out what was happening
in this Exec() method, and now I've got :
STATIC FUNCTION W32ThreadFunction( ) AS DWORD PASCAL
LOCAL msg IS _winMSG
LOCAL lRetVal AS LOGIC
local oNewSeesion AS CustomControl
oNewSession := CustomControl{ goOwner, 1000, Point{0,0},
Dimesion{0,0} }
// goOwner being the shell object
DO WHILE TRUE
lRetVal := GetMessage(@msg, oNewSession:Handle(), 0, 0)
IF !lRetVal
EXIT
ENDIF
DispatchMessage(@msg)
IF something specific occur
EXIT
ENDIF
ENDDO
RETURN 0
The above works 31 times on my xp box. After that the app just get
shut.
So why is that working 31 times and that's it ?
Nico
I really don't know what's happening, but you don't have to have a GUI just to
receive messages, and in a worker thread you really shouldn't have a GUI. If you
set up your own message pump to check for messages, you can use
PostThreadMessage to send Windows messages to the thread that has the message
pump. Then you need to make sure that when the message pump gets that kind of
message, that it knows what to do with it.
I have not used the VO GUI for years now, so I'm afraid I can't help you much
there.
Ginny
"nico" <ni...@microsurveys.co.uk> wrote in message
news:fde4aab8.0112...@posting.google.com...
I'm going to put all this theory into practice over the Christmas
break. Meanwhile, thanks again and have a good Christmas everyone...
Dave Francis
Ginny
"Dave Francis" <da...@suilven.com> wrote in message
news:8b6e85b9.01122...@posting.google.com...
Anyway, I've seen you are doing a session on MultiThreading in Devfest
next year... I look forward for that ! Thanks for your help and Joyeux
Noel et Bonne Annee !
Nico
See you at DevFest, and Merry Christmas and Happy New Year to you as well!
Ginny
"nico" <ni...@microsurveys.co.uk> wrote in message
news:fde4aab8.01122...@posting.google.com...