Delphi 2010: No thread vs threads - TSQLConnection and TSQLDataSet - multithreading

My previous question
From the above answer, means if in my threads has create objects, i will face the memory allocations/deallocations bottleneck?
I've a case that I need to create TSQLConnection and TSQLDataSet to query data from 5 tables of the database, each table has more than 10000 records. So I will create 5 threads, each thread accept a tablename as parameter via constructor. Unfortunately, i cannot get more obvious difference of time taken. I've write the following codes:
TMyThread = class(TThread)
private
FTableName: string;
protected
procedure Execute; override;
public
constructor Create(const CreateSuspended: Boolean; const aTableName: string);
reintroduce; overload;
end;
constructor TMyThread.Create(const CreateSuspended: Boolean; const aTableName);
begin
inherited Create(CreateSuspended);
FTableName := aTableName;
FreeOnTerminate := True;
end;
procedure TMyThread.Execute;
var C: TSQLConnection;
D: TDataSet;
begin
C := NewSQLConnection;
try
D := NewSQLDataSet(C, FTableName);
try
D.Open;
while not D.Eof do begin
// Do something
D.Next;
end;
finally
D.Free;
end;
finally
C.Free;
end;
end;
function NewSQLConnection: TSQLConnection;
begin
Result := TSQLConnection.Create(nil);
// Setup TSQLConnection
end;
function NewSQLDataSet(const aConn: TSQLConnection; const aTableName: string):
TSQLDataSet;
begin
Result := TSQLDataSet.Create(aConn);
Result.CommandText := Format('SELECT * FROM %s', [aTableName]);
Result.SQLConnection := aConn;
end;
Is there any advice or recommendation for this case?

My first thing I should do: take a look at the CPU time. Where is the bottleneck: is your application using 100% CPU in single user mode, then multi-threaded won't work (only on dual/quad core). But if your app in multi-threaded mode is not using much CPU you could have an other bottleneck: for example, the DB server is maybe using 100% CPU? Or your server HD is slow? Or slow network? Or maybe even the DBExpress database driver is not multi-threaded, so it only uses 1 thread at a time (you will notice low CPU on client and server on multicore).
By the way: yes, you should always try to minimize memory allocations. FastMM is not the best MM for heavy multithreaded: does not scale very well on multicore (you will never see 100% CPU in memory heavy apps). But nothing to bother about in normal apps. Only if this is the case, you could try TopMM: somewhat slower(?) but scales much better:
http://www.topsoftwaresite.nl/Downloads/TopMemory.pdf

Aha! You said you use SuperServer?
Firebird 1.5 Classic Server vs. Superserver
SuperServer:
No SMP support. On multi-processor Windows machines, performance can even drop dramatically as the OS switches the process between CPUs. To prevent this, set the CpuAffinityMask parameter in the configuration file firebird.conf.
So it uses only 1 core. You should use Classic Server (process per connection). Firebird has no true SMP support yet, will be in 3.0 version:
http://tracker.firebirdsql.org/browse/CORE-775

Actually I would like to see a CPU GRAPH with Process Explorer, like step 4 of this page:
http://www.brightrev.com/how-to/windows/53-five-uses-for-sysinternals-process-explorer.html
Because it shows CPU+mem+IO(!) in time. Please of both test app and firebird.
I think firebird is bound by IO (your HD), because in your first CPU screenshot, both have low CPU. Maybe you can increase firebird memory cache?
Btw: how many cores/cpu's do you have?

Related

Delphi - Is TDictionary thread safe

My idea is to use TDictionary to manage client connections on IdTCPServer. Here is a simple example code (not tested) for understanding purposes:
var
Dic: TDictionary<string, TIdContext>;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
Dic := TDictionary<string, TIdContext>.Create;
end;
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
Dic.Free;
end;
procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
Hostname: string;
begin
Hostname := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
if not Dic.ContainsKey(Hostname) then Dic.Add(Hostname, AContext);
end;
procedure TfrmMain.TCPServerDisconnect(AContext: TIdContext);
var
Hostname: string;
begin
Hostname := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
if Dic.ContainsKey(Hostname) then
begin
Dic[Hostname].Free;
Dic.Remove(Hostname);
end;
end;
Is this code thread safe?
In a word: No.
If you inspect the source of TDictionary you should quickly realise that there is no provision for thread-safety in the implementation itself. Even if it were, by having discrete calls to a Dic instance you have potential race conditions to contend with:
if Dic.ContainsKey(Hostname) then
begin
// In theory the Hostname key may be removed by another thread before you
// get a chance to do this : ...
Dic[Hostname].Free;
Dic.Remove(Hostname);
end;
You need to make your own use of Dic thread safe, and fortunately in this sort of example this is easily achieved using a monitor on the object itself:
MonitorEnter(Dic);
try
if not Dic.ContainsKey(Hostname) then
Dic.Add(Hostname, AContext);
finally
MonitorExit(Dic);
end;
// ....
MonitorEnter(Dic);
try
if Dic.ContainsKey(Hostname) then
begin
Dic[Hostname].Free;
Dic.Remove(Hostname);
end;
finally
MonitorExit(Dic);
end;
If you are not familiar with monitors in Delphi, in simple terms you can think of a monitor as a ready-to-use critical section supported by every TObject descendant (in older versions of Delphi which did not support these monitors you could have achieved the same thing with an explicit critical section).
To answer your specific question - no, TDictionary is NOT thread-safe, so you must protect access to it.
Your code is not handling the possibility of multiple clients behind a proxy/router connecting to the same server. They will all have the same PeerIP and HostName values. Those values are not unique enough by themselves to identify clients. You need to create your own unique identifiers, for instance by having your clients login to your server with a username, and then use that as your dictionary key instead.
And lastly, DO NOT free TIdContext objects! They are owned by TIdTCPServer and will be freed automatically after the OnDisconnect event handler has exited.

infinite loops in separate threads

I have some data base optimization routines that need to execute periodically. I am currently using a TTimer but the main VCL freezes and is very hacky ... I would like to know what the best method is to have a low cpu consumption and execute these routines. I think putting the routines in separate threads with low thread priority is the best way.
Any ideas ?
If possible, it is much better to just code all your threads to do the most important thing that needs to get done at that particular time. Messing with thread priorities can cause serious performance problems if you don't know exactly what you're doing. Instead, just code your threads like this:
Is there anything important to do? If so do it.
Is there anything not too important to do? If so, do a little of it.
Go to step 1.
Say you do use thread priorities. Imagine this:
A low priority task, A, grabs a lock on the database.
A normal priority task, B, requires lots of CPU time, it steals the CPU from the low priority task.
A normal priority task, C, requires access to the database. But it can't run because the low priority task holds the lock on the database and task B gets the CPU over task A.
Now, task C has to wait until task B is complete to get access to the database. But it should be timeslicing with task B.
One way of doing it is creating your "db optimization thread" something like:
type
// a record defining database connection
TConnectionSettings = record
DatabaseName: string;
Server: string;
Port: Word;
UserName: string;
Password: string;
end;
type
TDBOptimizationThread = class(TThread)
private
FConnection: TDatabaseConnection; // your database connection... I don't know what libraries you are using
FQuery: TQuery; // your specific db query
protected
procedure Execute; override;
public
constructor Create(AConnectionSettings: TConnectionSettings;
destructor Destroy; override;
end;
implementation
constructor TDBOptimizationThread.Create(AConnectionSettings: TConnectionSettings;
begin
inherited Create(True); // create suspended
//FreeOnTerminate := True; // if you want it to be freed when you terminate it
// create FConnection and FQuery objects
// setup FConnection parameters based on AConnectionSettings
end;
destructor TDBOptimizationThread.Destroy;
begin
// destroy objects
inherited Destroy;
end;
procedure TDBOptimizationThread.Execute;
begin
while NOT Terminated do
try
// check if it's time to run query
// you can use a private variable of TDateTime type that will hold
// last timestamp of when the query ran, etc.
if ItsTimeToRunQuery then begin
// check if we still have db connectivity
if NOT FConnection.Connected then
// ouch, try to connect...
FConnection.Connect;
FQuery.SQL.Text := 'Your optimization query';
FQuery.Execute; // or ExecSQL or whatever the method is based on your db library
end;
except
on E: Exception do begin
// log exception, something went wrong!!
end;
end;
end;
It is very important that your db connection is created and destroyed in this thread, otherwise you will have issues...
So, let's start a db optimization thread
...
var
LConnSettings: TConnectionSettings;
// you may want a private TDBOptimizationThread variable rather than
// a variable in a method, but I leave that to you
LDBOptimizationThread: TDBOptimizationThread;
begin
LConnSettings.Database := 'MyDatabase';
LConnSettings.Port := 1234;
LConnSettings.Server := 'localhost';
// continue with connection settings...
LDBOptimizationThread := TDBOptimizationThread.Create(LConnSettings);
LDBOptimizationThread.Start; // start it
end;
You can of course make it a low priority, but if your queries are not going to run for more than a few seconds at each time, I don't see a reason for that, but feel free to contradict.
IMHO, a low priority thread is the way to go for this kind of task. But you do not have to create different threads for each optimization routine, handle all of them with only one thread. So it will be easier for you to execute them in some specific order or with different frequencies and you will be sure that they do not get into way of each other (from the point of DB).

Thread.FreeOnTerminate := True, memory leak and ghost running

Years ago, I decided never to rely solely on setting a thread's FreeOnTerminate property to true to be sure of its destruction, because I discovered and reasoned two things at application's termination:
it produces a memory leak, and
after program's termination, the thread is still running somewhere below the keyboard of my notebook.
I familiarized myself with a workaround, and it did not bother me all this time. Until tonight, when again someone (#MartinJames in this case) commented on my answer in which I refer to some code that does not use FreeOnTerminate in combination with premature termination of the thread. I dove back in the RTL code and realized I may have made the wrong assumptions. But I am not quite sure about that either, hence this question.
First, to reproduce the above mentioned statements, this illustrative code is used:
unit Unit3;
interface
uses
Classes, Windows, Messages, Forms;
type
TMyThread = class(TThread)
FForm: TForm;
procedure Progress;
procedure Execute; override;
end;
TMainForm = class(TForm)
procedure FormClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FThread: TMyThread;
end;
implementation
{$R *.dfm}
{ TMyThread }
procedure TMyThread.Execute;
begin
while not Terminated do
begin
Synchronize(Progress);
Sleep(2000);
end;
end;
procedure TMyThread.Progress;
begin
FForm.Caption := FForm.Caption + '.';
end;
{ TMainForm }
procedure TMainForm.FormClick(Sender: TObject);
begin
FThread := TMyThread.Create(True);
FThread.FForm := Self;
FThread.FreeOnTerminate := True;
FThread.Resume;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FThread.Terminate;
end;
end.
Now (situation A), if you start the thread with a click on the form, and close the form right after the caption changed, there is a memory leak of 68 bytes. I assume this is because the thread is not freed. Secondly, the program terminates immediately, and the IDE is at that same moment back again in normal state. That in contrast to (situation B): when not making use of FreeOnTerminate and the last line of the above code is changed into FThread.Free, it takes (max.) 2 seconds from the disappearance of the program to the normal IDE state.
The delay in situation B is explained by the fact that FThread.Free calls FThread.WaitFor, both which are executed in the context of the main thread. Further investigation of Classes.pas learned that the destruction of the thread due to FreeOnTerminate is done in the context of the worker thread. This lead to the following questions on situation A:
Is there indeed a memory leak? And if so: is it important, could it be ignored? Because when an application terminates, doesn't Windows give back all its reserved resources?
What happens with the thread? Does it indeed run further somewhere in memory until its work is done, or not? And: is it freed, despite the evidence of the memory leak?
Disclaimer: For memory leak detection, I use this very simple unit as first in the project file.
Indeed, the OS reclaims all a process's memory when it terminates, so even if those 68 bytes refer to the non-freed thread object, the OS is going to take those bytes back anyway. It doesn't really matter whether you've freed the object at that point.
When your main program finishes, it eventually reaches a place where it calls ExitProcess. (You should be able to turn on debug DCUs in your project's linker options and step through to that point with the debugger.) That API call does several things, including terminating all other threads. The threads are not notified that they're terminating, so the cleanup code provided by TThread never runs. The OS thread simply ceases to exist.

How to implement thread which periodically checks something using minimal resources?

I would like to have a thread running in background which will check connection to some server with given time interval. For example for every 5 seconds.
I don't know if there is a good "desing pattern" for this? If I remember corretly, I've read somewehere that sleeping thread in its execute method is not good. But I might be wrong.
Also, I could use normal TThread class or OTL threading library.
Any ideas?
Thanks.
In OmniThreadLibrary, you would do:
uses
OtlTask,
OtlTaskControl;
type
TTimedTask = class(TOmniWorker)
public
procedure Timer1;
end;
var
FTask: IOmniTaskControl;
procedure StartTaskClick;
begin
FTask := CreateTask(TTimedTask.Create())
.SetTimer(1, 5*1000, #TTimedTask.Timer1)
.Run;
end;
procedure StopTaskClick;
begin
FTask.Terminate;
FTask := nil;
end;
procedure TTimedTask.Timer1;
begin
// this is triggered every 5 seconds
end;
As for sleeping in Execute - it depends on how you do it. If you use Sleep, then this might not be very wise (for example because it would prevent the thread to stop during the sleep). Sleeping with WaitForSingleObject is fine.
An example of TThread and WaitForSingleObject:
type
TTimedThread = class(TThread)
public
procedure Execute; override;
end;
var
FStopThread: THandle;
FThread: TTimedThread;
procedure StartTaskClick(Sender: TObject);
begin
FStopThread := CreateEvent(nil, false, false, nil);
FThread := TTimedThread.Create;
end;
procedure StopTaskClick(Sender: TObject);
begin
SetEvent(FStopThread);
FThread.Terminate;
FThread.Free;
CloseHandle(FStopThread);
end;
{ TTimedThread }
procedure TTimedThread.Execute;
begin
while WaitForSingleObject(Form71.FStopThread, 5*1000) = WAIT_TIMEOUT do begin
// this is triggered every 5 seconds
end;
end;
OTL timer implementation is similar to the TThread code above. OTL timers are kept in priority list (basically the timers are sorted on the "next occurence" time) and internal MsgWaitForMultipleObjects dispatcher in TOmniWorker specifies the appropriate timeout value for the highest-priority timer.
You could use an event and implement the Execute method of the TThread descendant by a loop with WaitForSingleObject waiting for the event, specifying the timeout. That way you can wake the thread up immediately when needed, e.g. when terminating.
If the thread runs for the life of the app, can be simply terminated by the OS on app close and does not need accurate timing, why bother with solutions that require more typing than sleep(5000)?
To add another means of achieving a 5-sec event it is possible to use the Multimedia Timer which is similar to TTimer but has no dependence on your application. After configuring it (you can setup one-shot or repetitive) it calls you back in another thread. By its nature it is very accurate (to within better than 1ms). See some sample Delphi code here.
The code to call the timer is simple and it is supported on all Windows platforms.
Use CreateWaitableTimer and SetWaitableTimer

Delphi - Updating a global string from a second thread

I am experimenting with multithreading in Delphi (XE) and have run into a problem with the use of a Global Variable between the main VCL thread and a second work thread.
My project involves a 2nd worker thread that scans through some files, and updates a globalvar string with the current filename its on. This globalvar is then picked up via a timer on the main VCL thread, and updates a statusbar.
I have noticed though that it occasionally comes up with a 'Invalid Pointer Operation'...or 'Out of Memory' or the work thread just stops responding (deadlock probably).
I therefore created a test app to identify and greatly increase the chance of error so i could see what's going on.
type
TSyncThread = class(TThread)
protected
procedure Execute; override;
end;
var
Form11: TForm11;
ProgressString : String;
ProgressCount : Int64;
SyncThread : TSyncThread;
CritSect : TRTLCriticalSection;
implementation
{$R *.dfm}
procedure TForm11.StartButtonClick(Sender: TObject);
begin
Timer1.Enabled := true;
SyncThread := TSyncThread.Create(True);
SyncThread.Start;
end;
procedure TForm11.StopbuttonClick(Sender: TObject);
begin
Timer1.Enabled := false;
SyncThread.Terminate;
end;
procedure TForm11.Timer1Timer(Sender: TObject);
begin
StatusBar1.Panels[0].Text := 'Count: ' + IntToStr(ProgressCount);
StatusBar1.Panels[1].Text := ProgressString;
end;
procedure TSyncThread.Execute;
var
i : Int64;
begin
i := 0;
while not Terminated do begin
inc(i);
EnterCriticalSection(CritSect);
ProgressString := IntToStr(i);
ProgressCount := i;
LeaveCriticalSection(CritSect);
end;
end;
initialization
InitializeCriticalSection(CritSect);
finalization
DeleteCriticalSection(CritSect);
I set the timer interval to 10ms so that it is reading a lot, whilst the worker thread is running flat out updating the global var string. Sure enough this app barely lasts a second when run before it comes up with the above errors.
My question is, does the read operation of the Global var in the VCL Timer need to be run in a critical section? - if so, why?. From my understanding it is only a read, and with the writes already running in a critical section, i cannot see why it runs into a problem. If i do put the read in the timer into a critical section as well - it works fine....but im unhappy just doing that without knowing why!
I am new to multithreading so would appreciate any help in explaining why this simple example causes all sorts of problems and if there is a better way to be accessing a string from a worker thread.
Delphi String is allocated on a heap, it is not a static buffer somewhere. The variable itself is just a pointer. When your reading thread accesses a String, and at the same time this very string is being deallocated by another thread, bad things happen. You are accessing already freed memory, possibly allocated again for something else, etc.
Even if this String was a static buffer, update operations are not atomic, therefore you could be using a corrupted string that is being updated at this very moment (half new data and half old).
So you need to protect your reading operations with the same critical section you used around the writing operations.

Resources