[fpc-pascal] RE: Threads executing in sequence instead of parallel
Jason P Sage
jasonpsage at jegas.org
Fri Sep 29 17:31:04 CEST 2006
Hi - I read enough of this topic to compel me to respond.
I have been working with Multi-threading in Free Pascal for a only a month
or so now and I learned a great deal - and I have resigned to accepting
there are design considerations I have had to adopt to get the results I
wanted - that some times seem a bit less than ideal - but the pay offs have
been wonderful. Let me digress a little...
First of all - THREADS running in a SERIAL fashion... Yup...
I had that problem and I resorted to the "SAMPLE" tthreads.pp I think its
called, as a starting point. It is an extremely simple example of
multi-threading working that comes with either FPC or the FPC source
I was fighting the serial execution - and then I ran that little tiny test
program - and it worked. I tried to fix my code some more - same problem -
but the little test program worked... so I finally (this is what I mean when
I say I resigned to design changes) adopted that EXACT example as the
foundation for how I would implement my THREADS.
I create my threads like a thread pool, I create them all suspended.
(Because that parts works pretty easy)...
I set up the EXECUTE MY THREAD... as a loop... BUT - Each iteration calls
its own SUSPEND method.... So it does a cycle and all I have to do is re
initialize the "parameters" it works with BEFORE I resume it.... So its...
as I call it "ready to fire" again, and then I just resume from the main
program that is handling all these threads.
Basically the test program has a working example of two threads looping at
the same time and the simple output shows they are truly multi-tasking... I
built my app into this same idea - with the addition that I suspend the loop
each go round.... the suspended threads in turn become my "ready to do
something" ones. If they aren't idle - they are either busy or trying to
find the meaning of life.
One of the biggest "issues" which is hard to debug if you aren't looking for
it ... is WHY does a thread stay working when it should have finished the
loop? It COULD be a bug in some dumb routine - but in many of my own cases -
- it is accessing data that I wanted "SHARED" by all the threads... I know
there is this critical section stuff and all that... but I found it simpler
to make a RECORD STRUCTURE INSIDE the Threaded class that has all the DATA
relevant to that INSTANCE - and then write "shared routines" that PASS this
structure by value - so there is less need to worry about sharing data
across the threads.
I follow two rules - if it MUST be shared - treat it read only.
If it can be copied to the thread's instance and does NOT really need to
actively traded between the threads, I put it in this record structure - I
refer to as "Thread CONTEXT".
Now - to handle the ABSOLUTELY MUST allow main app to talk with thread etc.
I keep it simple... each thread has a "structure" in the main program's
space allocated - and the main program can read an write to it, and the
thread can also... I try to keep the data simple - and less consequential to
synchronization isn't a big deal - like an IDLE FLAG - or sending a message
to the main program. I may write something out there, to a round robin like
queue, and manage the pointers, and set up a way for the main program to
read the info - when it can in a manner that doesn't interfere with the
thread and vice versa.
The moral of this story is four fold in my experience so far.
1: ITS Definitely worth it - the speed attained from multi threading, and in
many cases the simplicity of having "specific" tasks go away and work and
return when finished - well... I enjoy it.
2: Debugging a shared memory thing or one thread stomping another somehow -
is a REAL pain to debug... have a great error logging system you can include
or exclude with a compiler switch - they are priceless - never too big a log
file when debugging -- speaking for myself. My favorite thing is a NEST
COUNTER.. and my logs indent the nest level as periods "." so I can see when
routines are entered and exited. (I don't use the integrated environment
cause I can never get it configured right... I'm a command line junkie)
3: Keep it simple Silly Principle. Advanced methods not working? Resort to
something you KNOW works (like the little demo) and build from there. It's
often better to go around a mountain than climb the thing. Even though I'm
always up for challenges - sometimes ya just need to (Maybe you've heard the
famous comedian "Larry the Cable Guy" say this now famous slang term:
"Git-R-Dun" (Get it Done ;)
4: Threading IS NOT always the best solution. This has been mentioned in a
Lazarus WIKI I read. I'm building multi-user web applications and database
stuff etc. So its great for me. If I was making a FTP server like FileZilla
- I would do it also - even for the client - separate threads downloading
different files at once... But frankly - as many know - sometimes
alternatives can actually be faster - like multiplexing - or well managed
messaging systems - where program gathers work to do in a loop, then
processes each little task in order (or priority) one at time - ... depends
on the application however.
Have a great day all I have a ton of actual programming to do today - I love
my work - I love Free Pascal Too... I'm such a fan.
Jason P Sage
More information about the fpc-pascal