Delphi IDE hangs when I create a thread - multithreading

I have a problem that Delphi (2010) IDE and the program both hang during debugging when I run a thread.
Both windows do not respond. When I kill the program, IDE works again.
It took time, I had to delete pieces of my program and I found the problem.
It is caused by VirtualStringTree.
So if I put just empty VirtualStringTree (v. 5.5.3) on form, one button to execute TThread with just "Sleep(2000)" in Execute procedure and run such program under debugger, it hangs (usually at first click). When I remove the VST, it works.
I have also noticed that Windows Reporting Service is started but I haven't found anything in the Windows event log.
Does anyone have any idea how this is possible?
Full source here
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, VirtualTrees, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
VirtualStringTree1: TVirtualStringTree;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TTestThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TTestThread }
procedure TTestThread.Execute;
begin
FreeOnTerminate:=True;
Sleep(2000);
end;
{ TForm }
procedure TForm1.Button1Click(Sender: TObject);
begin
TTestThread.Create(False);
end;
end.
EDIT:
I have also tried to debug Delphi process. I attached from second to first IDE. When I click the button to start the thread, both IDEs hang. So I have tried with Delphi 7 which I also have installed. That worked. It stays in a loop somewhere in ntdll.NtWaitForMultipleObjects, KERNELBASE.WaitForMultipleObjectsEx, USER32.MsgWaitForMultipleObjects.
I have completely reinstalled Delphi, no change. It may also be related to this line in VirtualStringTree source: "WaitForSingleObject(WorkEvent, INFINITE);". When I remove it, it does not freeze. But I think it is necessary there.
Finally I installed Delphi XE and that works correctly. It is mysterious.

TTestThread is a descendant of TThread in your code but it still needs a variable declaration and a proper constructor call.
var
MyThread: TTestThread;
The proper call to instantiate it would be
MyThread := TTestThread.Create(False);
rather than trying to invoke the constructor as you have in the button click event.
Good luck and have fun.
RP

Related

Creating MainForm on a TThread

I have a Delphi 2010 application that exports a DLL and has the library header. It creates its MainForm in a TThread, like so:
var
ActiveThread: TActive;
type
TActive= class(TThread)
protected
procedure Execute; override;
end;
procedure TActive.Execute;
begin
Application.Initialize;
Application.CreateForm(MyForm, form);
Application.Run;
end;
begin
ActiveThread := TActive.Create(true);
ActiveThread.FreeOnTerminate := true;
ActiveThread.Resume;
end.
Whenever I load this DLL through the LoadLibrary function, the application runs fine. (Apparently it uses the thread that I passed to LoadLibrary as the main thread and has no issues)
But if I attempt to export this DLL to an actual EXE, by changing the generated output in Options -> Application. and changing the header from library to program and then build it and execute the output EXE instead of loading the DLL through the windows api, the application hangs when attempting to create the form, specifically at Application.CreateForm(MyForm, form);. If I remove the Application initialization from the thread and place it on the main routine, it runs just fine.
The form I'm trying to render is just an empty form. Any ideas?
When compiling this code as a program, at runtime it will try to terminate itself when end. is reached, before the worker thread even has a chance to run, which could possibly (and likely) happen after the Application object has been destroyed. You would have to wait for the worker thread to finish its work before letting the program exit, eg:
program MyProgram;
uses
Classes, Forms, MyForm;
type
TActive = class(TThread)
protected
procedure Execute; override;
end;
procedure TActive.Execute;
begin
Application.Initialize;
Application.CreateForm(TMyForm, MyForm);
Application.Run;
end;
var
ActiveThread: TActive;
begin
ActiveThread := TActive.Create(False);
ActiveThread.WaitFor;
ActiveThread.Free;
end.
But, there is really no good reason to ever use a worker thread like this, this defeats the whole purpose of using a thread, so you may as well just get rid of it altogether:
program MyProgram;
uses
Forms, MyForm;
begin
Application.Initialize;
Application.CreateForm(TMyForm, MyForm);
Application.Run;
end.
On the other hand, if you are trying to share common code between program and library projects, then you can wrap the Application code inside of a function and let the project decide which thread calls the function, eg:
unit MyApp;
interface
procedure RunMyApp;
implementation
uses
Forms, MyForm;
procedure RunMyApp;
begin
Application.Initialize;
Application.CreateForm(TMyForm, MyForm);
Application.Run;
end;
end.
program MyProgram;
uses
MyApp;
begin
RunMyApp;
end.
library MyLibrary
uses
Classes, MyApp;
type
TActive = class(TThread)
protected
procedure Execute; override;
end;
procedure TActive.Execute;
begin
RunMyApp;
end;
var
ActiveThread: TActive;
begin
ActiveThread := TActive.Create(True);
ActiveThread.FreeOnTerminate := True;
ActiveThread.Resume;
end.

Excel Application.Windows.Count returns 0

I use Windows 10, Delphi Berlin and Microsoft Office 2007. I try to get the number of opened Excel window. When I download Excel file and open it a seperated Excel runs so only one workbook exists in one Excel window.
I imported Microsoft Office 12.0 Object Library and wrote 2 procedures. Button1Click works with tExcelApplication and Button2Click does with CreateOleObject('excel.application'). After I run Excel the former works well but Count is recognized as an error just in the editor and the latter returns 0.
How Can I remove the annoying error message or get the _Excel to work?
type
TForm1 = class(TForm)
ExcelApplication1: TExcelApplication;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Caption := IntToStr(ExcelApplication1.Windows.Count);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
_Excel: Variant;
begin
_Excel := CreateOleObject('excel.application');
Button2.Caption := _Excel.windows.count;
end;
The message in the IDE is because you are using late bound COM. The method calls are dispatched at runtime and only at runtime do you find out whether or not the method exists. Because of that the compiler can't check the validity of your code. Your code is fine because it executes correctly, but the nature of late bound COM means the IDE thinks your code contains syntax errors. You just have to ignore it when using late bound COM.
You can switch instead to early bound COM and have the compiler be able to check the syntax of your code.
There are pros and cons of both approaches. Late bound can often yield simpler and more concise code. But at the expense of frustration when you only find out your mistakes at runtime.
If the value returned is zero then I guess the obvious conclusion is that there are no windows. The late bound code is creating a new instance of Excel, but the early bound code is attaching to an existing instance. To obtain an existing instance, if there is one, use GetActiveOleObject.

Threaded initialization and cleanup in delphi

I was reading the answer to another question here about the need to run coinitialize and couninitialize to connect to ADO objects. I need to do something similar to perform soap calls in a thread.
Is there a way to override a TThread object to have something automatically run before and after execute inside the thread?
For this example, we're converting to a SOAP backend and have to do a ton of that and it would save a bit of time to just override a new SOAP friendly TThread than to add coinitialize and couninitialze to every thread. But in general, initializing and cleaning up the thread inside the thread sometimes seems like a good idea. Right now it seems like you can only do one or the other.
Perhaps you want something like this:
type
TMyThread = class sealed(TThread)
private
FOnBeforeExecute: TProc;
FOnExecute: TProc;
FOnAfterExecute: TProc;
protected
procedure Execute; override;
public
property OnBeforeExecute: TProc read FOnBeforeExecute write FOnBeforeExecute;
property OnExecute: TProc read FOnExecute write FOnExecute;
property OnAfterExecute: TProc read FOnAfterExecute write FOnAfterExecute;
end;
procedure TMyThread.Execute;
begin
if Assigned(OnBeforeExecute) then
OnBeforeExecute;
try
if Assigned(OnExecute) then
OnExecute;
finally
if Assigned(OnAfterExecute) then
OnAfterExecute;
end;
end;
I made it a sealed class so that you cannot replace Execute with something that breaks the design. The added benefit is that you can decouple the thread procedure from the implementing class using events.
If you want to take care on specific initialization and finalization doing it with events like in David's answer means that you have to assign those events for every thread you create. And that means either adding a specific constructor to pass them in or creating the threads in suspended mode.
Personally I don't really like having to remember to do all those things and would therefore go for a more polymorphic solution:
type
TInitializeFinalizeThread = class(TThread)
protected
procedure InitializeExecution; virtual;
procedure FinalizeExecution; virtual;
procedure InternalExecute; virtual;
procedure Execute; override;
end;
procedure TInitializeFinalizeThread.Execute;
begin
InitializeExecution;
try
InternalExecute;
finally
FinalizeExecution;
end;
end;
Threads needing to do Ole Stuff could then have a common base that takes care of the initialization and finialization:
type
TOleThread = class(TInitializeFinalizeThread)
protected
procedure InitializeExecution; override;
procedure FinalizeExecution; override;
end;
procedure TOleThread.InitializeExecution;
begin
CoInitialize;
end;
procedure TOleThread.FinalizeExecution;
begin
CoUninitialize;
end;
This means that classes that are actually going to do something can just inherit from TOleThread and be assured that the initialization and finalization have been taken care of, so they only need to override InternalExecute.
type
TWordMailMergeThread = class(TInitializeFinalizeThread)
protected
procedure InternalExecute; override;
end;
procedure TWordMailMergeThread.InternalExecute;
begin
// Whatever you need this to do.
end;
Though they are of course free to override the InitializeExecution and FinalizeExecution methods to set up and quit the connection to the OleServer (Word in this example) instead of doing it in the InternalExecute.

Multithreaded file write via an existing object

Application Description:
I have an application that allows a user to run multiple concurrent queries via threads (up to 100 at once).
I have a class that I use for logging errors. If an error occurs in the application, I create an instance of the class and call a procedure to write the error to a log file.
Question:
I need to make the error logging code thread safe. I've noticed that if a lot of threads are running at the same time and generating the same error (e.g. cannot connect to database), I'm getting i/o error 32 (caused by the application attempting to write to a file that's already open).
As a quick and dirty fix, I've put the code that writes to file in a try... except block inside a repeat loop. If there is an exception (e.g. the file has already been opened by another instance of the class, kicked off by another thread), then it sets a flag to "false". The loop continues to execute until the flag is "true" (i.e. no error writing to file), as follows:
procedure TErrorLogging.logError(error: string);
var
f: textfile;
ok: boolean;
begin
repeat
ok := true;
try
assignfile(f, fLogFilename);
if fileExists(fLogFilename) then append(f) else rewrite(f);
writeln(f, error);
closefile(f);
except
ok := false;
end;
until ok;
end;
I'm aware that the correct way to protect blocks of code is by using Critical Sections, but I'm not sure how I'd implement that, given that there are a number of different threads that use the logging class, and each instance of the thread has its own instance of the logging class that it uses to write to file (so they're not all just synchronizing against the same block of code).
The options, as I can see them:
Use the code as above. Are there any issues with leaving this code as it is? It's a quick and dirty fix, but it works.
Use a global TCriticalSection (how?).
Use a single procedure somewhere that creates an instance of the logging class, which the threads will synchronize against (which defeats the object of having a logging class, I suppose).
Creating instance of a logging class whenever you want to append log entry is wrong as well as opening and closing a log file over and over again. I would personally use one instance of a class which internally uses a string list and whose basic methods are thread safe. Something like this:
type
TErrorLog = class
private
FList: TStringList;
FLock: TRTLCriticalSection;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure Add(const ErrorText: string);
procedure SaveToFile(const FileName: string);
end;
implementation
{ TErrorLog }
constructor TErrorLog.Create;
begin
inherited Create;
InitializeCriticalSection(FLock);
FList := TStringList.Create;
end;
destructor TErrorLog.Destroy;
begin
EnterCriticalSection(FLock);
try
FList.Free;
inherited Destroy;
finally
LeaveCriticalSection(FLock);
DeleteCriticalSection(FLock);
end;
end;
procedure TErrorLog.Clear;
begin
EnterCriticalSection(FLock);
try
FList.Clear;
finally
LeaveCriticalSection(FLock);
end;
end;
procedure TErrorLog.Add(const ErrorText: string);
begin
EnterCriticalSection(FLock);
try
FList.Add(ErrorText);
finally
LeaveCriticalSection(FLock);
end;
end;
procedure TErrorLog.SaveToFile(const FileName: string);
begin
EnterCriticalSection(FLock);
try
FList.SaveToFile(FileName);
finally
LeaveCriticalSection(FLock);
end;
end;
Not knowing Delphi, as a general design rule (if possible), I would have your logError function insert into a thread safe Array, ArrayList, Queue object or such that you have available, and then have it write to the file in the background, perhaps every 5-10 seconds or so. This should not only take care of the i/o problem, but should also scale to thousands of writes per second in case you want to log other events for debugging or such.

Exist any drawback if i use a callback function inside of a thread to comunicate with the main thread of my app?

i wrote a Thread.descendent class, and to comunicate my thread with the main thread i use a callback function so i am wondering if is a valid solution or instead i must use windows messages?
type
TMyCallBack= procedure(const Param1,Param2: string) of object;
TMyThread= class(TThread)
private
P1 : string;
P2 : string;
MyCallBack : TMyCallBack;
procedure Process;
public
Constructor Create(CallBack : TMyCallBack); overload;
destructor Destroy; override;
procedure Execute; override;
end;
procedure TMyThread.Process;
begin
FCallBack(P1,P2);
end;
constructor TMyThread.Create(CallBack : TMyCallBack);
begin
inherited Create(False);
FreeOnTerminate := True;
MyCallBack := CallBack;
end;
procedure TMyThread.Execute;
begin
while True and not Terminated do
begin
AResult:= FListener.GetResult(Param1,Param2,5000);
if not VarIsNull(AResult) then
begin
P1:=AResult.Value1;
P2:=AResult.Value2;
Synchronize(Process);
end;
end;
end;
As long as you use Synchronize you should be fine.
If you run the callback via Synchronize, it's OK, as most Delphi implementations:
create a callback structure, containing the callback and an event handle
append the callback structure to a locked global list
post a message to the main thread, to wake it from WaitMessage or alike
wait on the event until the callback completes
This may or may not be better than using raw window messages, as:
the callback list is checked in clearly defined places and as such its not as much eligible for reentrancy issues
for the same reasons, its certainly a bit less performant
it may cause problems with modal windows and native popup menus, which allow sent message processing, but may bypass the synchronization list handling in some cases
As long as the callback processing must mot be waitable/cancellable, and you can tell for sure it doesn't do anything that might cause sent message processing (as most windows-message-related routines do!), you may prefer using SendMessage, with appropriate parameter marshaling.

Resources