Sunday, August 3, 2008

Threads in Delphi

If we have a time consuming loop in our Delphi program , then till the loop ends , the interface will be stuck. It won't process any messages. You can avoid this problem by adding Application.ProcessMessages inside the loop. So the messages get processed inside the loop also. Application.ProcessMessages is practically useless because the application will only receive messages at the time the call is made. It won't release the interface. Using a thread, on the other hand, frees up the interface because the process is running completely separate from the main thread of the program where the interface resides. So regardless of what you execute within a loop that is running in a separate thread, your interface will never get locked up.
You can have multiple threads to process different independent operations.

To use a thread object in your application, you must create a new descendant of TThread. To create a descendant of TThread, choose FileNewOther from the main menu. In the New Items dialog box, double-click Thread Object and enter a class name, such as TMyThread. To name this new thread, check the Named Thread check box and enter a thread name (VCL applications only). Naming your thread makes it easier to track the thread while debugging. After you click OK, the Code editor creates a new unit file to implement the thread. For more information on naming threads, see Naming a thread.Unlike most dialog boxes in the IDE that require a class name, the New Thread Object dialog box does not automatically prepend a 'T' to the front of the class name you provide.

The automatically generated unit file contains the skeleton code for your new thread class. If you named your thread TMyThread, it would look like the following:
unit Unit1;
interface
uses Classes;
type TMyThread = class(TThread)
private { Private declarations }
protected procedure Execute; override;
end;

implementation{ TMyThread }

procedure TMyThread.Execute;
begin { Place thread code here }
end;

end.

Initializing a thread
If you want to write initialization code for your new thread class, you must override the Create method. Add a new constructor to the declaration of your thread class and write the initialization code as its implementation. This is where you can assign a default priority for your thread and indicate whether it should be freed automatically when it finishes executing.

Default priority
Priority indicates how much preference the thread gets when the operating system schedules CPU time among all the threads in your application. Use a high priority thread to handle time critical tasks, and a low priority thread to perform other tasks. To indicate the priority of your thread object, set the Priority property.

If writing a Windows-only application, Priority values fall along a scale, as described in the following table:
Value : Priority
tpIdle : The thread executes only when the system is idle. Windows
: won't interrupt other threads to execute a thread with tpIdle priority.
tpLowest : The thread's priority is two points below normal.
tpLower : The thread's priority is one point below normal.
tpNormal : The thread has normal priority.
tpHigher : The thread's priority is one point above normal.
tpHighest : The thread's priority is two points above normal.
tpTimeCritical : The thread gets highest priority.

constructor TMyThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
Priority := tpIdle;
end;

When threads are freed
Usually, when threads finish their operation, they can simply be freed. In this case, it is easiest to let the thread object free itself. To do this, set the FreeOnTerminate property to True.
There are times, however, when the termination of a thread must be coordinated with other threads. For example, you may be waiting for one thread to return a value before performing an action in another thread. To do this, you do not want to free the first thread until the second has received the return value. You can handle this situation by setting FreeOnTerminate to False and then explicitly freeing the first thread from the second.

Execute method
The Execute method is your thread function. You can think of it as a program that is launched by your application, except that it shares the same process space. Writing the thread function is a little trickier than writing a separate program because you must make sure that you don't overwrite memory that is used by other threads in your application. On the other hand, because the thread shares the same process space with other threads, you can use the shared memory to communicate between threads.

When you use objects from the class hierarchy, their properties and methods are not guaranteed to be thread-safe. That is, accessing properties or executing methods may perform some actions that use memory which is not protected from the actions of other threads. Because of this, a main thread is set aside to access VCL and CLX objects. This is the thread that handles all Windows messages received by components in your application.

If all objects access their properties and execute their methods within this single thread, you need not worry about your objects interfering with each other. To use the main thread, create a separate routine that performs the required actions. Call this separate routine from within your thread's Synchronize method. For example:

procedure TMyThread.ClickButton;
begin
Button1.Click;
end;

procedure TMyThread.Execute;
begin
...
Synchronize(ClickButton);
...
end;

Synchronize waits for the main thread to enter the message loop and then executes the passed method.

If you want to use variables that are global to all the routines running in your thread, but not shared with other instances of the same thread class. You can do this by declaring thread-local variables. Make a variable thread-local by declaring it in a threadvar section. For example,

threadvar x : integer;

declares an integer type variable that is private to each thread in the application, but global within each thread.

5 comments:

sabita said...

really g8t!!!!! born to be a delphi pgrmr ;)

Neutrino said...

Cheers, awesome article! ;)

kthxbai2u said...

Threads are nice :) I quickly read the article, I already have threads :) nice article though,

and Delphi always 4 life :)

Anonymous said...

Very nice post ... I'm learning Delphi threading and this post really helped me out.
Well done and thank you.

Anonymous said...

Can some one please type the entire code for thread.. because im new to delphi and Since the code is incomplete i cannot execute it... kindly some one write the entire program for me.