Você está na página 1de 5

17/06/13

Delphi threading by example

EMBAR C ADER O HO ME

LO C ATIO N | ENGLISH | LO G O N

Watch, Follow, & Connect with Us Share This

COMMUNITIES
EDN Delphi

ARTICLES

BLOGS

RESOURCES

DOWNLOADS

HELP

Delphi threading by example


By: Wim De Cleen
Abstract: An example using the Windows API.

IN THIS ARTICLE An example with the Windows API Why synchronize? Getting started Critical sections Starting the thread Handling the messages Putting things together.

An example with the Windows API


By Wim De Cleen, Software Engineer with Electromatic Sint-Niklaas NV (Belgium) Threads are somewhat overwhelming until you have written some threading code and gotten experience with their ins and outs. This article will introduce you to the art of threading and synchronization. I use the Windows API calls to show you how it really works -- the hard truth. I wrote an example that searches for a specific string in multiple files. As the threads search, real-time synchronized information is sent to the main form. Of course, the data could also be sendtto another thread or application. The more you think about it, the more you see the power of threading. When a thread is running, it runs on its own without wondering what other threads are doing. That is why one thread can calculate a sum of two numbers -- let's say a and b, while another thread comes to life and changes the value of a. This is not what we want! So we need a shell around the global variables so that no other thread can access them. Then, when the calculations are done, we might remove the shell to give other threads in the system access to the data once more. The easiest way to construct such a shell is to use critical sections. We will use these as a start. (Incidentally, synchronization bugs like this can bite you when you are using VCL components, which are generally not thread-safe. When you start updating controls from different threads everything may seem fine...but the bug will present itself some time in the future. Then it is up to you to find the synchronization bug. Believe me, this can take a while. Debugging threads is really frustrating! Delphi's TThread class has a method called synchronize, and if it did everything we wanted then there would be no need for this article. TThread lets you specify a method that needs to be synchronized with the main thread (the thread of the VCL). This is handy if you can afford to spend time waiting for synchronization, but in systems where milliseconds are crucial you can't use this method: It halts the execution of the thread during synchronization. My alternative method is based on messages. With the function PostMessage you can deliver messages to any thread in the system without waiting for the result. The message is just placed onto the message queue of the receiving thread and stays there until the receiving thread comes to life. At that time the message is handled. All that time your thread continues to run. Critical sections are the simplest synchronizers possible. They are fast because they can be used only within the same process. A critical section can be used to protect global variables but you must perform the coordination yourself. You can't bind a variable to a critical section programmatically; it must be done logically. Let's say we want to protect any access to the variables a and b. Here's how to do it with the critical sections approach: / / g l o b a lv a r i a b l e s v a rC r i t i c a l S e c t i o n :T R T L C r i t i c a l S e c t i o n ; a ,b :i n t e g e r ; / / b e f o r et h et h r e a d ss t a r t s I n i t i a l i z e C r i t i c a l S e c t i o n ( C r i t i c a l S e c t i o n ) ; / / i nt h et h r e a d E n t e r C r i t i c a l S e c t i o n ( C r i t i c a l S e c t i o n ) ; / / F r o mn o wo n ,y o uc a ns a f e l ym a k e / / c h a n g e st ot h ev a r i a b l e s . i n c ( a ) ; i n c ( b ) ; / / E n do fs a f eb l o c k L e a v e C r i t i c a l S e c t i o n ( C r i t i c a l S e c t i o n ) ; See? Nothing to it. This approach lets you create multiple threads without worrying about the effect on global variables. When creating a thread without the TThread class, always use the BeginThread function from the SysUtils unit. It is specifically written to use Pascal functions and it encapsulates the CreateThread winapi call. Let's take a look at the declaration and step through the parameters. B e g i n T h r e a d ( S e c u r i t y A t t r i b u t e s :P o i n t e r ; S t a c k S i z e :L o n g W o r d ; T h r e a d F u n c :T T h r e a d F u n c ; P a r a m e t e r :P o i n t e r ; C r e a t i o n F l a g s :L o n g W o r d ; v a rT h r e a d I d :L o n g W o r d ) :I n t e g e r ; SecurityAttributes: a pointer to a security record, used only in windows NT, fill in nil StackSize: the initial stack size of the thread. The default value is 1MB. If you think this is too small fill in the desired size, otherwise if not fill in 0. ThreadFunc: This is the function that will be executed while the thread is running. This is mostly a function with a while loop inside. The prototype is function(Parameter: Pointer): Integer Parameter: This is a pointer to a parameter, which can be anything you like. It will be passed to the thread function as the parameter pointer. CreationFlags: This flag determines whether the thread starts immediately or it is suspended until ResumeThread is called. Use CREATE_SUSPENDED for suspended and 0 for an immediate start. ThreadID: This is a var parameter that will return the ThreadID of the thread.

Why synchronize?

RATING

Download Trial Buy Now Try Delphi XE4 free for 30 days
New Instant Trial!

Getting started

Critical sections

Starting the thread

Webinars on demand!

edn.embarcadero.com/article/22411

1/5

17/06/13

Delphi threading by example


Handling messages sent to a form is simple in Delphi. You just have to declare a procedure with the following prototype: procedure(var Message:TMessage). This procedure must be declared as a method of your form class. By using the message directive you bind a message to the function. In the form declaration it looks like this: c o n s t T H _ M E S S A G E=W M _ U S E R+1 ; t y p e F o r m 1=c l a s s ( T F o r m ) p r i v a t e p r o c e d u r eH a n d l e M e s s a g e ( v a rM e s s a g e : T M e s s a g e ) ;m e s s a g eT H _ M E S S A G E ; p u b l i c e n d ; From now on every message sent to the form with the message parameter TH_MESSAGE will invoke the HandleMessage procedure. We can send a message with the PostMessage function which looks like the following" P o s t M e s s a g e( H a n d l e :H W N D ;M e s s a g e :C a r d i n a l ;W P a r a m :i n t e g e r ;L P a r a m : i n t e g e r ) Handle: The handle of the receiving thread or receiving form. Message: The messageconstant. WParam: An optional parameter. LParam: An optional parameter. The example program uses messages to deliver information to the main form from within threads. First I declared the message constants and the submessage constants. Submessages will be passed through the LParam. c o n s t T H _ M E S S A G E=W M _ U S E R+1 ;/ / T h r e a dm e s s a g e T H _ F I N I S H E D=1 ; / / T h r e a dS u b M e s s a g e / / E n do ft h r e a d / / W P a r a m=T h r e a d I D T H _ N E W F I L E=2 ; / / T h r e a dS u b m e s s a g e / / S t a r t e dn e wf i l e T H _ F O U N D=3 ; / / T h r e a dS u b m e s s a g e / / F o u n ds e a r c hs t r i n gi nF i l e T H _ E R R O R=4 ; / / T h r e a dS u b M e s s a g e / / E r r o r-W P a r a m=E r r o r T h e nt h ei n f o r m a t i o nr e c o r d s ,w h i c hw i l lb ep a s s e dt h r o u g hW P a r a m : t y p e / / R e c o r df o rf o u n di t e m s ,w i l lo c c u rw h e n / / L P a r a m=T H _ F O U N D ,W P a r a mw i l lb e / / P F o u n d R e c o r d P F o u n d R e c o r d=^ T F o u n d R e c o r d ; T F o u n d R e c o r d=r e c o r d T h r e a d I D :C a r d i n a l ; F i l e n a m e :s t r i n g ; P o s i t i o n :C a r d i n a l ; e n d ; / / R e c o r df o rn e wf i l e s ,w i l lo c c u rw h e n / / L P a r a m=T H _ N E W F I L E ,W P a r a mw i l lb e / / P N e w F i l e R e c o r d P N e w F i l e R e c o r d=^ T N e w F i l e R e c o r d ; T N e w F i l e R e c o r d=r e c o r d T h r e a d I D :C a r d i n a l ; F i l e n a m e :s t r i n g ; e n d ; Since we need some information about the threads we declare an info record for them: / / R e c o r dt oh o l dt h ei n f o r m a t i o nf r o mo n et h r e a d T T h r e a d I n f o=r e c o r d A c t i v e :B o o l e a n ; T h r e a d H a n d l e :i n t e g e r ; T h r e a d I d :C a r d i n a l ; C u r r e n t F i l e :s t r i n g ; e n d ; Finally we declare the TMainForm class, which contains the message handler: / / T h eM a i nf o r mo ft h ea p p l i c a t i o n T M a i n F o r m=c l a s s ( T F o r m ) b t S e a r c h :T B u t t o n ; M e m o :T M e m o ; O p e n D i a l o g :T O p e n D i a l o g ; e d S e a r c h :T E d i t ; S t r i n g G r i d :T S t r i n g G r i d ; L a b e l 1 :T L a b e l ; p r o c e d u r eb t S e a r c h C l i c k ( S e n d e r :T O b j e c t ) ; p r o c e d u r eF o r m C r e a t e ( S e n d e r :T O b j e c t ) ; p r o c e d u r eF o r m D e s t r o y ( S e n d e r :T O b j e c t ) ; p r o c e d u r ee d S e a r c h C h a n g e ( S e n d e r :T O b j e c t ) ; p r i v a t e T h r e a d I n f o :a r r a y [ 0 . . 4 ]o fT T h r e a d I n f o ; / / H o l d st h ei n f o r m a t i o no ft h et h r e a d s p r o c e d u r eT h r e a d M e s s a g e ( v a rM e s s a g e :T M e s s a g e ) ; m e s s a g eT H _ M E S S A G E ;/ / M e s s a g e H a n d l e r f u n c t i o nT h r e a d I D T o I n d e x ( T h r e a d I D :C a r d i n a l ) : i n t e g e r ; p u b l i c e n d ;

Handling the messages

Putting things together.

Delphi
Curtir 11.008 pessoas curtiram Delphi.

More social media choices: Delphi on Google+ @RADTools on Twitter @FireMonkeyTeam Twitter

ARTICLE TAGS

Delphi
Thre ad
tthread

multi-threading

edn.embarcadero.com/article/22411

2/5

17/06/13

Delphi threading by example


In the implementation section we declare our global variables, the critical section, a search string, and the list of files we will be searching. v a rC r i t i c a l S e c t i o n :T R T L C r i t i c a l S e c t i o n ; / / C r i t i c a ls e c t i o np r o t e c t st h ef i l e l i s t F i l e L i s t :T S t r i n g L i s t ; / / L i s to ff i l e n a m e st ob es e a r c h e d S e a r c h S t r i n g :s t r i n g ; / / S t r i n gt ob es e a r c h e di ne v e r yf i l e Then follows the thread function, this is the function that delivers all the work for the thread. It will be passed to the begin thread function. f u n c t i o nF i n d I n F i l e ( d a t a :P o i n t e r ) :I n t e g e r ; v a rF i l e S t r e a m :T F i l e S t r e a m ; C h :c h a r ; C u r r e n t , L e n :I n t e g e r ; F o u n d R e c o r d :P F o u n d R e c o r d ; N e w F i l e R e c o r d :P N e w F i l e R e c o r d ; F i l e n a m e :s t r i n g ; S e a r c h :s t r i n g ; F i l e s D o n e :B o o l e a n ; b e g i n R e s u l t : =0 ; F i l e s D o n e : =F a l s e ; w h i l en o tF i l e s D o n ed o b e g i n C u r r e n t : =1 ; E n t e r C r i t i c a l S e c t i o n ( C r i t i c a l S e c t i o n ) ; / / T r yt oc a t c ht h ec r i t i c a ls e c t i o n S e a r c h : =S e a r c h S t r i n g ; / / A c c e s st h es h a r e dv a r i a b l e s / / A r et h e r es t i l lf i l e sa v a i l a b l e i fF i l e L i s t . C o u n t=0t h e n b e g i n / / L e a v et h ec r i t i c a ls e c t i o n / / w h e nt h e r ea r en of i l e sl e f t L e a v e C r i t i c a l S e c t i o n ( C r i t i c a l S e c t i o n ) ; / / L e a v et h ew h i l el o o p b r e a k ; e n d e l s e b e g i n / / R e a dt h ef i l e n a m e F i l e n a m e : =F i l e L i s t . S t r i n g s [ 0 ] ; / / D e l e t et h ef i l ef r o mt h el i s t F i l e L i s t . D e l e t e ( 0 ) ; / / L e a v et h ec r i t i c a ls e c t i o n L e a v e C r i t i c a l S e c t i o n ( C r i t i c a l S e c t i o n ) ; / / I n f o r mM a i n F o r mo fN e wF i l e N e w ( N e w F i l e R e c o r d ) ; N e w F i l e R e c o r d ^ . F i l e n a m e : =F i l e n a m e ; N e w F i l e R e c o r d ^ . T h r e a d I D : =G e t C u r r e n t T h r e a d I D ; P o s t M e s s a g e ( M a i n F o r m . H a n d l e , T H _ M E S S A G E ,T H _ N E W F I L E , I n t e g e r ( N e w F i l e R e c o r d ) ) ; L e n : =L e n g t h ( S e a r c h ) ; t r y F i l e S t r e a m : =T F i l e S t r e a m . C r e a t e ( F i l e n a m e ,f m O p e n R e a do rf m S h a r e E x c l u s i v e ) ; e x c e p t P o s t M e s s a g e ( M a i n F o r m . H a n d l e ,T H _ M E S S A G E , T H _ E R R O R ,E R R O R _ C O U L D _ N O T _ O P E N _ F I L E ) ; c o n t i n u e ; e n d ; / / T h es e a r c ha l g o r i t h m ,p r e t t ys i m p l e , / / t h ee x a m p l ei sn o ta b o u ts e a r c h i n g w h i l eF i l e S t r e a m . R e a d ( C h , 1 ) =1d o b e g i n I fC h=S e a r c h [ C u r r e n t ]t h e n b e g i n I n c ( C u r r e n t ) ; i fC u r r e n t>L e nt h e n b e g i n / / F o u n dt h es e a r c hs t r i n g , / / i n f o r mM a i n F o r mo fo u rs u c c e s s N e w ( F o u n d R e c o r d ) ; F o u n d R e c o r d ^ . F i l e n a m e : =F i l e n a m e ; F o u n d R e c o r d ^ . P o s i t i o n : =F i l e S t r e a m . P o s i t i o n ; F o u n d R e c o r d ^ . T h r e a d I D : =G e t C u r r e n t T h r e a d I D ; P o s t M e s s a g e ( M a i n F o r m . H a n d l e , T H _ M E S S A G E ,T H _ F O U N D , I n t e g e r ( F o u n d R e c o r d ) ) ; e n d ; e n d e l s e b e g i n F i l e S t r e a m . P o s i t i o n : = F i l e S t r e a m . P o s i t i o n-( C u r r e n t-1 ) ; C u r r e n t : =1 ; e n d ; e n d ; F i l e S t r e a m . F r e e ; e n d ; e n d ; / / A l ld o n ei n f o r mM a i n F o r mo fe n d i n g P o s t M e s s a g e ( M a i n F o r m . H a n d l e , T H _ M E S S A G E ,T H _ F I N I S H E D ,G e t C u r r e n t T h r e a d I D ) ; e n d ;

edn.embarcadero.com/article/22411

3/5

17/06/13

Delphi threading by example


Another important procedure is the message handler, which -- drum roll, please -- handles the messages. It also frees the record pointers. p r o c e d u r eT M a i n F o r m . T h r e a d M e s s a g e ( v a rM e s s a g e :T M e s s a g e ) ; v a rF o u n d R e c o r d :P F o u n d R e c o r d ; N e w F i l e R e c o r d :P N e w F i l e R e c o r d ; T h r e a d I n d e x :i n t e g e r ; C o u n t e r :i n t e g e r ; E n d e d :b o o l e a n ; b e g i n c a s eM e s s a g e . W P a r a mo f T H _ F I N I S H E D : b e g i n T h r e a d I n d e x : =T h r e a d I D T o I n d e x ( M e s s a g e . L P a r a m ) ; i fT h r e a d I n d e x=1t h e nE x i t ; / / I n v a l i dt h r e a d I Ds h o u l dn e v e ra p p e a r C l o s e H a n d l e ( T h r e a d I n f o [ T h r e a d I n d e x ] . T h r e a d H a n d l e ) ; / / F r e et h et h r e a dm e m o r y s p a c e S t r i n g G r i d . C e l l s [ 3 , T h r e a d I n d e x + 1 ] : =' F a l s e ' ; / / U p d a t et h es t r i n g g r i d T h r e a d i n f o [ T h r e a d I n d e x ] . A c t i v e : =F a l s e ; / / U p d a t et h eT h r e a d I n f oa r r a y E n d e d : =T r u e ; f o rc o u n t e r : =0t o4d o i fT h r e a d I n f o [ T h r e a d I n d e x ] . A c t i v et h e n b e g i n E n d e d : =F a l s e ; b r e a k ; e n d ; i fE n d e dt h e nb t S e a r c h . E n a b l e d : =T r u e ; e n d ; T H _ N E W F I L E : b e g i n N e w F i l e R e c o r d : =P N e w F i l e R e c o r d ( M e s s a g e . L P a r a m ) ; T h r e a d I n d e x : =T h r e a d I D T o I n d e x ( N e w F i l e R e c o r d ^ . T h r e a d I D ) ; i fT h r e a d I n d e x=1t h e nE x i t ; / / I n v a l i dt h r e a d I Ds h o u l dn e v e ra p p e a r S t r i n g G r i d . C e l l s [ 2 , T h r e a d I n d e x + 1 ] : = N e w F i l e R e c o r d ^ . F i l e n a m e ;/ / U p d a t eS t r i n g G r i d T h r e a d I n f o [ T h r e a d I n d e x ] . C u r r e n t F i l e : = N e w F i l e R e c o r d ^ . F i l e n a m e ;/ / U p d a t eT h r e a d I n f o D i s p o s e ( N e w F i l e R e c o r d ) ; / / A l li n f o r m a t i o ni su s e dn o wf r e et h ep o i n t e r e n d ; T H _ F O U N D : b e g i n F o u n d R e c o r d : =P F o u n d R e c o r d ( M e s s a g e . L P a r a m ) ; T h r e a d I n d e x : =T h r e a d I D T o I n d e x ( F o u n d R e c o r d ^ . T h r e a d I D ) ; i fT h r e a d I n d e x=1t h e nE x i t ; / / I n v a l i dt h r e a d I Ds h o u l dn e v e ra p p e a r M e m o . L i n e s . A d d ( F o u n d R e c o r d ^ . F i l e n a m e+'P o s i t i o n : ' +I n t T o S t r ( F o u n d R e c o r d ^ . P o s i t i o n ) ) ; D i s p o s e ( F o u n d R e c o r d ) ; / / A l li n f o r m a t i o ni su s e dn o wf r e et h ep o i n t e r e n d ; T H _ E R R O R : b e g i n T h r e a d I n d e x : =T h r e a d I D T o I n d e x ( M e s s a g e . L P a r a m ) ; i fT h r e a d I n d e x=1t h e nE x i t ; / / I n v a l i dt h r e a d I Ds h o u l dn e v e ra p p e a r M e m o . L i n e s . A d d ( ' E r r o r :C o u l dn o to p e nf i l e' +T h r e a d I n f o [ T h r e a d I n d e x ] . C u r r e n t F i l e ) ; e n d ; e n d ; e n d ; You don't need to worry about pasting the functions and classes together. I have included the complete example in a Zip file so you can see it working right away. This is not a complete explanation of threading. It's barely a beginning. But I hope it will serve as a starting point for your own exploration. I wish I had had an example to guide me when I started working with threads!

LATEST COMMENTS
Move mouse over comment to see the full text

Reply Posted by Craven Weasel on May 20 2013

Delphi threading by example This is a very useful thread, Thank you!


Reply Posted by Abdul khadar Shaik on Mar 01 2013

re: Delphi threading by example You can.But you have to pay attenction on DeadLocks
Reply Posted by kepcee gursel on Mar 16 2010

Delphi threading by example thank you sohbet cinsel sohbet


Reply Posted by Linar Siboro on Jul 16 2007

Delphi threading by example I'm a newbie in Delphi n I just learn about thread. I'm so lucky finding this tutorial :) I have a question. Is possible to make more than one critical section?? bcoz I have more than one variables...
Reply Posted by Craven Weasel on Jun 14 2007

edn.embarcadero.com/article/22411

4/5

17/06/13
Delphi threading by example Thanks a lot.
Reply Posted by richard fritz on Jul 15 2000

Delphi threading by example

Delphi threading by example as someone just learning about threads, and who needed some explanation along with example(s) , i was lucky enough to find an excellent online tutorial on using threads in Delphi, and i would...
Reply Posted by Wim De Cleen on Jul 11 2000

re: Delphi threading by example This can be done in the same way as in the example Try this: procedure Test(param: integer); var Form: TForm; begin Form := TForm(param); Form.Caption := 'It can be...
Reply Posted by Reid Abel on Jul 10 2000

Delphi threading by example Interesting and very practical article. Thanks. I have a question: the integer parameters (LParam and WParam) are shown as Integer(record). So, record structures are passed as parameters by casting...
Reply Posted by Wim Verhaeghen on Jul 06 2000

Delphi threading by example Contratulations for a real & neat article.


Se rve r R e sponse from : ETNASC 04

Copyright 1994 - 2013 Embarcadero Technologies, Inc. All rights reserved.

Site Map

edn.embarcadero.com/article/22411

5/5

Você também pode gostar