?
Solved

multi-thread application

Posted on 2004-10-05
12
Medium Priority
?
389 Views
Last Modified: 2010-08-05
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
0
Comment
Question by:MauricioGaviria
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
  • 2
  • +2
12 Comments
 
LVL 6

Expert Comment

by:david_barker
ID: 12229637
I think you are going to have to give more details, like where the code breaks.
0
 

Author Comment

by:MauricioGaviria
ID: 12230528
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(listaEquipos:TStringList;idCmd:String);
    procedure FOnDoneParsing(Sender: TObject);

  public
    { Public declarations }
  end;

var
  serverGui: TserverGui;

implementation

uses hiloArchivo;

{$R *.dfm}

procedure TserverGui.Button1Click(Sender: 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(listaEquipos,'540');
end;

procedure TServerGui.iniciarCopiaArchivo(listaEquipos:TStringList;idCmd:String);
begin
    ThreadsRunning := 1;
    with TEscribirArchivo.Create(listaEquipos, 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(listaPCs:TStringList;idComandoExe:String); virtual; abstract;
  public
    constructor Create(lista: TStringList; idCmd: String);
  end;

  TEscribirArchivo = class(ThiloEscrituraArchivo)
  protected
    procedure escribir_a_Archivo(listaPCs:TStringList;idComandoExe:String);
  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.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

{ hiloEscrituraArchivo }
constructor ThiloEscrituraArchivo.Create(lista: TStringList; idCmd: String);
begin
    listaEqps := TStringList.Create;
    listaEqps := lista;
    idComando := idCmd;
    FreeOnTerminate := True;
    inherited Create(False);
end;
procedure ThiloEscrituraArchivo.Execute;
begin
    { Place thread code here }
    escribir_a_Archivo(listaEqps,idComando);
end;
procedure ThiloEscrituraArchivo.mostrarProgreso;
begin
    serverGui.RichEdit1.Lines.Add('ok');
    serverGui.RichEdit1.Lines.Add(listaEqps.Strings[0]);
end;
procedure TEscribirArchivo.escribir_a_Archivo(listaPCs:TStringList;idComandoExe:String);
begin
    listaPCs.SaveToFile('comandos.txt');
    Synchronize(mostrarProgreso);
end;
end.
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12230538
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.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 13

Expert Comment

by:BlackTigerX
ID: 12230610
the problem might be because you are passing a reference to all threads to that list

try something like this:

procedure TServerGui.iniciarCopiaArchivo(listaEquipos:TStringList;idCmd:String);
begin
    ThreadsRunning := 1;
    with TEscribirArchivo.Create(listaEquipos, 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;
0
 
LVL 6

Accepted Solution

by:
vadim_ti earned 1500 total points
ID: 12232798
Hi, I think you need to do 2 changes:

1) in procedure Button1Click you need to create TStringList

listaEquipos := TStringList.Create;

before adding items

2) in constructor

ThiloEscrituraArchivo

instead of
 listaEqps := lista;

have to be
   listaEqps.AddStrings(lista);
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12235451
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.Create(lista: TStringList; idCmd: String);
begin
    listaEqps := TStringList.Create;
    listaEqps := lista;
    idComando := idCmd;
    FreeOnTerminate := True;
    inherited Create(False);
end;

Should be:
constructor ThiloEscrituraArchivo.Create(lista: TStringList; idCmd: String);
begin
    inherited Create(False);
    listaEqps := TStringList.Create;
    listaEqps := lista;
    idComando := idCmd;
    FreeOnTerminate := True;
end;

0
 
LVL 6

Expert Comment

by:vadim_ti
ID: 12235506
Alex:

i do not think you are right, must be:

constructor ThiloEscrituraArchivo.Create(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
0
 

Author Comment

by:MauricioGaviria
ID: 12238736
thanks a lot
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12243682
@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.Create(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;
0
 
LVL 6

Expert Comment

by:vadim_ti
ID: 12244206
ok, i regular do the same, but in this case, there are no difference

below is thread constructor with my comments

constructor TThread.Create(CreateSuspended: 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(@SThreadCreateError, [SysErrorMessage(GetLastError)]);
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.Create(lista: TStringList; idCmd: String);
begin
    listaEqps := TStringList.Create;
    listaEqps := lista;
    idComando := idCmd;
    FreeOnTerminate := True;
    inherited Create(False);
end;

0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12247342
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.
0
 
LVL 6

Expert Comment

by:vadim_ti
ID: 12247613
thanks
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

649 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question