Preface
Goal: An overview of multithreading in Free Pascal.
I have used multithreading capability,
using TThread
about fiteen years ago,
but it is limited for windows.
I wonder what option do I have for concurrency in Pascal. Does it have go like channel?
And I finally find the answer.
Free Pascal is still using TThread
, as main option.
But this time works with Linux.
13: Pure FPC Example
My first option is, the pure FPC example.
Official Documentation
This article is my exploration of the official documentation:
Actually I have trouble following this documentation. So I put a few tricks from the forum to solve the problem.
Using CThread in Linux
The official documentation state clearly for unix or linux user,
you need this ifdef
directive.
Program ThreadTest;
uses
{$ifdef unix}CThreads, {$endif} SysUtils;
Windows user should pay attention to this, since I omit the directive, after the next example.
Conversion Issue
While compiling, I face this warning:
Warning: Conversion between ordinals and pointers is not portable.
❯ fpc 31-thread-test
Free Pascal Compiler version 3.2.2 [2022/03/02] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling 31-thread-test.pp
31-thread-test.pp(20,21) Warning: Conversion between ordinals and pointers is not portable
31-thread-test.pp(24,23) Warning: Conversion between ordinals and pointers is not portable
31-thread-test.pp(27,21) Warning: Conversion between ordinals and pointers is not portable
31-thread-test.pp(39,21) Warning: Conversion between ordinals and pointers is not portable
Linking 31-thread-test
43 lines compiled, 0.2 sec
4 warning(s) issued
Just warning, but pretty annoying.
Quick and Dirty Solution
For this to work, I use directive to surpress the warning message. It means, the problem is still persist in the code.
{$hints off}{$warnings off}
Writeln('thread ',longint(p),' started');
thri:=0;
while (thri<stringlen) do begin
s:=s+'1'; { create a delay }
writeln('thread ',longint(p),' thri ',thri,' Len(S)= ',length(s));
inc(thri);
end;
Writeln('thread ',longint(p),' finished');
InterLockedIncrement(finished);
f:=0;
{$hints on}{$warnings on}
And also the main program entry point.
Begin
finished:=0;
{$hints off}{$warnings off}
for i:=1 to threadcount do
BeginThread(@f,pointer(i));
{$hints on}{$warnings on}
while finished<threadcount do ;
Writeln(finished);
End.
The Result
Enjoy the output:
❯ ./31-thread-test
thread 1 started
thread 2 started
thread 1 thri 0 Len(S)= 1
thread 2 thri 0 Len(S)= 1
thread 3 started
thread 3 thri 0 Len(S)= 1
thread 1 thri 1 Len(S)= 2
thread 1 thri 2 Len(S)= 3
...
The example from official documentation is actually works.
Linking Issue
However, this is not the last warning I found.
“crtbeginS.o” not found, this will probably cause a linking failure.
“crtendS.o” not found, this will probably cause a linking failure.
I must have been mad, but I thought the code won’t run. It got me frustrated fo a while. Until I realize it is just a warning. And the code run well.
❯ fpc 31-thread-test
Free Pascal Compiler version 3.2.2 [2022/03/02] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling 31-thread-test.pp
Linking 31-thread-test
31-thread-test.pp(47,1) Warning: "crtbeginS.o" not found, this will probably cause a linking failure
31-thread-test.pp(47,1) Warning: "crtendS.o" not found, this will probably cause a linking failure
47 lines compiled, 0.2 sec
2 warning(s) issued
Now, how to get rid of the warning?
Checking Library
I have checked my system, and the library is there.
❯ ls /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0 "crt*"
32 crtendS.o libgcc.a
cc1 crtfastmath.o libgcc_eh.a
cc1plus crtprec32.o libgcov.a
collect2 crtprec64.o liblto_plugin.so
crtbegin.o crtprec80.o lto1
crtbeginS.o include lto-wrapper
crtbeginT.o include-fixed plugin
crtend.o install-tools
So the issue should lies in the configuration.
FPC Configuration
And I finally found that, the path didn’t match the configuration file. All I need just to alter the configuration file.
# path to the gcclib
#ifdef cpui386
-Fl/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/32
#endif
#ifdef cpux86_64
-Fl/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0
#endif
:
And voila! Nomore FPC
warning.
TThread
Most of the code here, I just copy and paste from the official documentation. And reduce things I don’t need.
Official Documentation
Introducing
TThread
.
You’d better read this first before continue.
MyThread Interface
For convenience, I made an example class in its own unit. So we can change later easier.
{$mode objFPC}
unit MyThread;
interface
Uses CThreads, Classes;
type
TMyThread = class(TThread)
protected
procedure Execute; override;
public
Constructor Create(CreateSuspended : boolean);
end;
MyThread Implementation
The implementation is, short.
implementation
constructor TMyThread.Create(CreateSuspended : boolean);
begin
inherited Create(CreateSuspended);
FreeOnTerminate := True;
end;
procedure TMyThread.Execute;
begin
WriteLn('In thread');
end;
end.
Just that short, really.
All we need is tell the execute
method what to do.
Using MyThread
Now it is time to see the Thread in action. Nothing fancy here. Except, it just run in CLI, without bothering with GUI or such IDE.
uses MyThread;
var
AThread : TMyThread;
begin
// This way it doesn't start automatically
AThread := TMyThread.Create(True);
AThread.Start;
end.
We are using AThread.Start
to start the thread.
With the result similar as below:
❯ ./32-tthread
In thread
Wait? Just that output? Where is the concurrency anyway?
Well, for this step,
all you need to know is that TThread
works in CLI.
Whether in linux or windows.
We are going to explore more.
What is Next 🤔?
We are going to go deeper with TThread
in CLI.
Consider continue reading [ Pascal - Playing with Records - Part Six ].