3
I needed to add some threads to carry out certain processes in the background.
This thread accesses the methods of a Webservice and also performs operations in the database.
I create all the objects I need to use in this thread within itself to avoid concurrent access with components outside it. Like IBDatabase
and the IBTransaction
(use IBX components).
So my thread’s kind of like this:
TThreadAtualizarDados = class(TThread)
private
FIBDatabase: TIBDatabase;
FIBTransaction: TIBTransaction;
public
constructor Create(AIBDatabase: TIBDatabase); reintroduce;
destructor Destroy; override;
procedure Execute; override;
end;
Like I said, everything I need to use in the thread I instill in myself.
constructor TThreadAtualizarDados.Create(AIBDatabase: TIBDatabase);
begin
inherited Create(false);
FreeOnTerminate := true;
// conexão com o banco de dados
FIBDatabase := TIBDatabase.Create(nil);
FIBDatabase.LoginPrompt := false;
FIBDatabase.DatabaseName := AIBDatabase.DatabaseName;
FIBDatabase.Params.Text := AIBDatabase.Params.Text;
// controle transacional
FIBTransaction := TIBTransaction.Create(nil);
FIBTransaction.DefaultDatabase := FIBDatabase;
FIBDatabase.DefaultTransaction := FIBTransaction;
end;
The processes I wish her to carry out are successfully carried out until her execution is complete.
destructor TThreadAtualizarDados.Destroy;
begin
inherited;
if FIBTransaction.Active then
FIBTransaction.Commit;
// Comentados porque está causando erro
//
// FIBDatabase.Free;
// FIBTransaction.Free;
end;
The lines that end the connection and the transaction are commented because if they are executed, a certain time later (short time) after the thread is finished (method output Destroy
) an error is generated.
Error message:
Programa.exe faulted with message: 'application-defined Exception (code 0xc000041d) at 0x77071a91'.
What does not characterize a Access Violation.
What might be causing this error, and what to do to resolve it?
Adding more information:
The thread is instilled this way:
procedure TFrmAtualizaDados.p_Iniciar_Atualizacao;
begin
TThreadAtualizarDados.Create(Dm.IdbIntsys);
end;
That is, no external treatment is done in the thread. I’m not passing her reference to any variable so that I could be finishing it manually, or anything else. Since I have set her parameter to execute as soon as she is instituted inherited Create(false);
and had her destroy herself automatically after finalizing her method Execute
, with the FreeOnTerminate := true;
, then I just instacing the parameters and let it work.
Even, I have even other classes in the thread that I instâncio, as TStringList
and TList
that do not give problems, only the instances of the components of the database generate problems if they are released from memory (.Free
).
Another detail is that the error message is triggered only when I change the application to Delphi, in mode debug.
Of course the option "Stop on Delphi Exceptions", in "Debuger Options", is enabled.
Can you post the code that invokes the threads? See that setting
FreeOnTerminate := true;
thedestroy
will already be automatically invoked at the end of the methodExecute
. That is, if you are invoking thefree
thread, the code of thedestroy
will execute twice.– Caffé
The design you made there is pretty cool. A pity it doesn’t work. Worse is the lack of documentation on these components! I think you’re experiencing yet another sad limitation of Delphi :-/ Maybe these components just can’t work on a second thread, maybe instances share some state that isn’t thread safe, maybe they just don’t work if they’re not pasted into a form or datamodule. All these limitations I have experienced in several Delphi components. Good luck there!
– Caffé
Tiago, a possible outline solution would be to create the connection externally in a pool and just allocate it to the thread. Another test I would do would be to release the transaction first, set
FIBDatabase.DefaultTransaction := nil
, then set theFIBDatabase.Connected := False
and then destroy the objectFIBDatabase
. Can you tell me if any of these tests were helpful?– Caputo
Try calling the
destroy
of objects withSynchronize()
to destroy in the main thread. It may be some problem with the Debugger– Caputo
I will then answer the/
– Caputo
Thiago, I don’t know if
TThread
implements something in your destructor that can affect your code. In general, it is better to invokeinherited
only after your own code ondestroy
.– Caffé
I agree with @Caffé, inherited should be the last call on the destructor, including Ctrl+shift+C even leaves room for it, follow the IDE’s suggestion
– EProgrammerNotFound
Thiago, in Destroy the "inherited" has to be the last instruction.
– Ricardo Alves Carvalho