Here's a more complete tutorial to read.
Threads are a great way to do a large amount of processing in your program while allowing the visual part of your program to remain responsive. If you can split up the processing into several threads you can take advantage of modern processors multi core capability and complete a job in a fraction of the time.
Lazarus programs can use threads in GUI and Console programs. If you use threading in your program you should define the compiler option
-dUseCThreads
. This can be done in Project->Options->Compiler Options->Other - Custom Options. This does nothing under Windows but on any *nix it includes a needed threadmanager. If your program crashes with the first use of thread.Start; then this is probably your problem.Now that your program is thread enabled here's some basic information about threads. You must subclass the
TThread
type and make your own thread type and override the Execute
method.The
Execute
method is never called directly in your program. It is the method the thread will run on it's own when it is started. If you are using MyThread.Execute
then you are making a mistake.Here's a basic example of a new thread type
type
TFooThread = class(TThread)
protected
procedure Execute; override;
end;
...
implementation
procedure TFooThread.Execute;
begin
// do stuff
end;
To create an instance of your thread you can use
FooThread := TFooThread.Create(True);
The argument
True
creates the thread in suspended state, meaning the OS thread is created but not yet run. If you use False
then the thread begins and Execute
is called immediately. You can of course make your own constructor with whatever parameters you need and use inherited Create(False)
there.To start a thread you should use
FooThread.Start
. FooThread.Resume
is deprecated as well as .Suspend
which is not reliable on *nix's and can cause your program to hang.Now your thread is running and working and making your life easier. Your program is snappier and you decide that you need to make your program display the progress your thread is making processing some data.
So in TFooThread.Execute you add Form1.ProgressBar1.Position := SomeValue.
Bad idea. It may work or your program could immediately crash or it might cause some other harder to find error that happens later. Never ever do this.
The reason this is so bad is because the GUI part of your program is run in a separate thread (duh!) and has it's own memory area. Changing the memory in one thread from another needs to be coordinated carefully. You should never change a LCL control value from a thread other than the main process.
A way to update the main thread from another thread is the
Synchronize(@SomeProc)
method. The Syncronize
method, which is called within a created thread, causes the thread to pause and wait for the main thread to call a procedure. Also see CritialSections from the link at the beginning of this articleWhen your thread terminates you should assume that any code in it's destructor may be called a thread other than your main process thread, especially if you set
FreeOnTerminate
to True
. If you assign a handler for the OnTerminate property then that procedure will be run in the main thread.After all the code in the
Execute
method is run your thread cannot be restarted. You will have to free and create another instance of the thread type you need. It's common to include while not Terminated do begin ... end
around the code inside the Execute
method in order to use a thread multiple times without having to recreate it.Most of the basic stuff I have run into is now covered. Go code, or read some more: Threading Tutorial on the Wiki