MauricioGaviria
asked on
multi-thread application
When trying to execute a multi-thread application in Delphi 6, it gives an error with message:
faulted with message: access violation at 0x005517e8: write of address 0x38010b12. Process stopped.
What does this error mean? How can I solve this situation
faulted with message: access violation at 0x005517e8: write of address 0x38010b12. Process stopped.
What does this error mean? How can I solve this situation
I think you are going to have to give more details, like where the code breaks.
ASKER
ok
this is the source
-------------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------
main Unit
-------------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TserverGui = class(TForm)
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
Button1: TButton;
RichEdit1: TRichEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
ThreadsRunning: Integer;
procedure iniciarCopiaArchivo(listaE quipos:TSt ringList;i dCmd:Strin g);
procedure FOnDoneParsing(Sender: TObject);
public
{ Public declarations }
end;
var
serverGui: TserverGui;
implementation
uses hiloArchivo;
{$R *.dfm}
procedure TserverGui.Button1Click(Se nder: TObject);
var
listaEquipos : TStringList;
idComando : String;
begin
listaEquipos.Add('pp');
listaEquipos.Add('pp2');
listaEquipos.Add('pp3');
listaEquipos.Add('pp4');
listaEquipos.Add('pp5');
listaEquipos.Add('pp6');
listaEquipos.Add('pp7');
listaEquipos.Add('pp8');
listaEquipos.Add('pp9');
listaEquipos.Add('pp10');
listaEquipos.Add('pp11');
listaEquipos.Add('pp12');
listaEquipos.Add('pp13');
iniciarCopiaArchivo(listaE quipos,'54 0');
end;
procedure TServerGui.iniciarCopiaArc hivo(lista Equipos:TS tringList; idCmd:Stri ng);
begin
ThreadsRunning := 1;
with TEscribirArchivo.Create(li staEquipos , idCmd) do
OnTerminate := FOnDoneParsing;
Button1.Enabled := False;
end;
procedure TServerGui.FOnDoneParsing( Sender: TObject);
begin
Dec(ThreadsRunning);
if ThreadsRunning = 0 then
begin
Button1.Enabled := True;
end;
end;
end.
-------------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------
unit thread
-------------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------
unit hiloArchivo;
interface
uses
Classes;
type
ThiloEscrituraArchivo = class(TThread)
private
{ Private declarations }
listaEqps : TStringList;
idComando : String;
protected
procedure Execute; override;
procedure mostrarProgreso;
procedure escribir_a_Archivo(listaPC s:TStringL ist;idComa ndoExe:Str ing); virtual; abstract;
public
constructor Create(lista: TStringList; idCmd: String);
end;
TEscribirArchivo = class(ThiloEscrituraArchiv o)
protected
procedure escribir_a_Archivo(listaPC s:TStringL ist;idComa ndoExe:Str ing);
end;
implementation
uses excaliburAdminCode;
{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example,
Synchronize(UpdateCaption) ;
and UpdateCaption could look like,
procedure hiloEscrituraArchivo.Updat eCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }
{ hiloEscrituraArchivo }
constructor ThiloEscrituraArchivo.Crea te(lista: TStringList; idCmd: String);
begin
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
procedure ThiloEscrituraArchivo.Exec ute;
begin
{ Place thread code here }
escribir_a_Archivo(listaEq ps,idComan do);
end;
procedure ThiloEscrituraArchivo.most rarProgres o;
begin
serverGui.RichEdit1.Lines. Add('ok');
serverGui.RichEdit1.Lines. Add(listaE qps.String s[0]);
end;
procedure TEscribirArchivo.escribir_ a_Archivo( listaPCs:T StringList ;idComando Exe:String );
begin
listaPCs.SaveToFile('coman dos.txt');
Synchronize(mostrarProgres o);
end;
end.
this is the source
--------------------------
main Unit
--------------------------
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TserverGui = class(TForm)
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
Button1: TButton;
RichEdit1: TRichEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
ThreadsRunning: Integer;
procedure iniciarCopiaArchivo(listaE
procedure FOnDoneParsing(Sender: TObject);
public
{ Public declarations }
end;
var
serverGui: TserverGui;
implementation
uses hiloArchivo;
{$R *.dfm}
procedure TserverGui.Button1Click(Se
var
listaEquipos : TStringList;
idComando : String;
begin
listaEquipos.Add('pp');
listaEquipos.Add('pp2');
listaEquipos.Add('pp3');
listaEquipos.Add('pp4');
listaEquipos.Add('pp5');
listaEquipos.Add('pp6');
listaEquipos.Add('pp7');
listaEquipos.Add('pp8');
listaEquipos.Add('pp9');
listaEquipos.Add('pp10');
listaEquipos.Add('pp11');
listaEquipos.Add('pp12');
listaEquipos.Add('pp13');
iniciarCopiaArchivo(listaE
end;
procedure TServerGui.iniciarCopiaArc
begin
ThreadsRunning := 1;
with TEscribirArchivo.Create(li
OnTerminate := FOnDoneParsing;
Button1.Enabled := False;
end;
procedure TServerGui.FOnDoneParsing(
begin
Dec(ThreadsRunning);
if ThreadsRunning = 0 then
begin
Button1.Enabled := True;
end;
end;
end.
--------------------------
unit thread
--------------------------
unit hiloArchivo;
interface
uses
Classes;
type
ThiloEscrituraArchivo = class(TThread)
private
{ Private declarations }
listaEqps : TStringList;
idComando : String;
protected
procedure Execute; override;
procedure mostrarProgreso;
procedure escribir_a_Archivo(listaPC
public
constructor Create(lista: TStringList; idCmd: String);
end;
TEscribirArchivo = class(ThiloEscrituraArchiv
protected
procedure escribir_a_Archivo(listaPC
end;
implementation
uses excaliburAdminCode;
{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example,
Synchronize(UpdateCaption)
and UpdateCaption could look like,
procedure hiloEscrituraArchivo.Updat
begin
Form1.Caption := 'Updated in a thread';
end; }
{ hiloEscrituraArchivo }
constructor ThiloEscrituraArchivo.Crea
begin
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
procedure ThiloEscrituraArchivo.Exec
begin
{ Place thread code here }
escribir_a_Archivo(listaEq
end;
procedure ThiloEscrituraArchivo.most
begin
serverGui.RichEdit1.Lines.
serverGui.RichEdit1.Lines.
end;
procedure TEscribirArchivo.escribir_
begin
listaPCs.SaveToFile('coman
Synchronize(mostrarProgres
end;
end.
It means that on address 0x005517e8 there's a function trying to either read or write data on address 0x38010b12. However, this memory address is protected for some reason and the action cannot be executed. You don't have access, thus you get an access violation.
If you want to get a more detailed answer, please give more details about your application. ;-)
It is most likely that some component or object or function is trying to access something in one thread that has been freed in the other thread. You could try debugging the code but it's better to write log information to a log file.
If you want to get a more detailed answer, please give more details about your application. ;-)
It is most likely that some component or object or function is trying to access something in one thread that has been freed in the other thread. You could try debugging the code but it's better to write log information to a log file.
the problem might be because you are passing a reference to all threads to that list
try something like this:
procedure TServerGui.iniciarCopiaArc hivo(lista Equipos:TS tringList; idCmd:Stri ng);
begin
ThreadsRunning := 1;
with TEscribirArchivo.Create(li staEquipos , idCmd) do
begin
OnTerminate := FOnDoneParsing;
Sleep(20) //just give time for this thread to assign that list to its internal list
end;
Button1.Enabled := False;
end;
try something like this:
procedure TServerGui.iniciarCopiaArc
begin
ThreadsRunning := 1;
with TEscribirArchivo.Create(li
begin
OnTerminate := FOnDoneParsing;
Sleep(20) //just give time for this thread to assign that list to its internal list
end;
Button1.Enabled := False;
end;
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
One simple advise, which not many people follow anyway: Don't use your native language for class names, variable names and anything else. Try using English names for them. Not that it matters much, but when you need help from people like us at EE who don't understand your native language, your code snippets become a bit easier to read. It also helps if you ever plan to sell the sourcecode to some other party. But as I said, not many people do this anyway.
vadim_ti is right. Use listaEqps.AddStrings(lista );
But the real flaw is here:
constructor ThiloEscrituraArchivo.Crea te(lista: TStringList; idCmd: String);
begin
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
Should be:
constructor ThiloEscrituraArchivo.Crea te(lista: TStringList; idCmd: String);
begin
inherited Create(False);
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
end;
vadim_ti is right. Use listaEqps.AddStrings(lista
But the real flaw is here:
constructor ThiloEscrituraArchivo.Crea
begin
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
Should be:
constructor ThiloEscrituraArchivo.Crea
begin
inherited Create(False);
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
end;
Alex:
i do not think you are right, must be:
constructor ThiloEscrituraArchivo.Crea te(lista: TStringList; idCmd: String);
begin
listaEqps := TStringList.Create;
listaEqps.AddStrings(lista ); // <==
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
please tell me what a difference where you place
inherited Create;
i do not understand
i do not think you are right, must be:
constructor ThiloEscrituraArchivo.Crea
begin
listaEqps := TStringList.Create;
listaEqps.AddStrings(lista
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
please tell me what a difference where you place
inherited Create;
i do not understand
ASKER
thanks a lot
@vadim_ti, you are wrong... You must FIRST call the inherited Create, then initialize whatever you want to be initialized. If you do it the other way around, you risk that the inherited create will clear some of the data you've just initialized. With destructors, you call the inherited method as last method, but with constructors you MUST call the inherited create first.
Because, do you realise that the default behaviour of TObject.Create is to zero the memory used by the component? It checks the size, then cleans it. Thus if you've added some data in it... Well, you know the risk.
The constructor initializes the data, thus you first want to call the inherited stuff, so that part is correctly initialized, then add your own stuff. With destructors it's the other way around, cleaning your stuff first before the inherited destructor gets the chance to clean the rest.
In most cases I just do this:
constructor ThiloEscrituraArchivo.Crea te(lista: TStringList; idCmd: String);
begin
inherited Create(TRUE); // Create it suspended.
listaEqps := TStringList.Create;
listaEqps.AddStrings(lista ); // <==
idComando := idCmd;
FreeOnTerminate := True;
RESUME; // Resume the thread.
end;
Because, do you realise that the default behaviour of TObject.Create is to zero the memory used by the component? It checks the size, then cleans it. Thus if you've added some data in it... Well, you know the risk.
The constructor initializes the data, thus you first want to call the inherited stuff, so that part is correctly initialized, then add your own stuff. With destructors it's the other way around, cleaning your stuff first before the inherited destructor gets the chance to clean the rest.
In most cases I just do this:
constructor ThiloEscrituraArchivo.Crea
begin
inherited Create(TRUE); // Create it suspended.
listaEqps := TStringList.Create;
listaEqps.AddStrings(lista
idComando := idCmd;
FreeOnTerminate := True;
RESUME; // Resume the thread.
end;
ok, i regular do the same, but in this case, there are no difference
below is thread constructor with my comments
constructor TThread.Create(CreateSuspe nded: Boolean);
begin
inherited Create; // do nothing (TObject constructor)
AddThread; // add thread to threads list
FSuspended := CreateSuspended; // it is ok
FCreateSuspended := CreateSuspended; // it is ok
// we do not use thread handle
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);
if FHandle = 0 then
raise EThread.CreateResFmt(@SThr eadCreateE rror, [SysErrorMessage(GetLastEr ror)]);
end;
what i wanted to say , in this case there is no difference where you call inherited constructor.
i even checked 2 cases to be sure.
i do not understand one thing, why FreeOnTerminate works with this constructor:
constructor ThiloEscrituraArchivo.Crea te(lista: TStringList; idCmd: String);
begin
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
below is thread constructor with my comments
constructor TThread.Create(CreateSuspe
begin
inherited Create; // do nothing (TObject constructor)
AddThread; // add thread to threads list
FSuspended := CreateSuspended; // it is ok
FCreateSuspended := CreateSuspended; // it is ok
// we do not use thread handle
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);
if FHandle = 0 then
raise EThread.CreateResFmt(@SThr
end;
what i wanted to say , in this case there is no difference where you call inherited constructor.
i even checked 2 cases to be sure.
i do not understand one thing, why FreeOnTerminate works with this constructor:
constructor ThiloEscrituraArchivo.Crea
begin
listaEqps := TStringList.Create;
listaEqps := lista;
idComando := idCmd;
FreeOnTerminate := True;
inherited Create(False);
end;
The TObject.Create isn't doing nothing! At least not with all Delphi versions. The fact that it just happens to work this time isn't really professional, though. That's just my main objection with that method of calling the inherited method as last one. The reason that FreeOnTerminate just happens to work is probably because it is not cleared in the inherited create methods. Basically, that's a bug because it means it could contain any kind of value.
All I'm saying is that you cannot rely that it continues to work with the next Delphi version.
All I'm saying is that you cannot rely that it continues to work with the next Delphi version.
thanks