Jump to content
ErikT

Access violation when creating thread

Recommended Posts

I am trying to make a thread, and thought that I had understood how to pass initial values to that thread while creating it. I have used examples from Embarcadero, combined with examples from threads in this forum.

However, I get an access violation at the first line of code in the constructor.

 

Type definition of thread and form:

type
  TPingThread = class(TThread)
  private
    LocOwnIP : in_addr;
    LocFromIP : Byte;
    LocToIP : Byte;
    Progress : Byte;
    LastByte : Byte;
    AddressList : TStringList;
    LocOwner : TComponent;
    Ping1 : TPing;
  protected
    procedure Execute; override;
  public
    constructor Create(AOwner : TComponent; OwnIP : in_addr; FromIP : Byte; ToIP : Byte); reintroduce;
    destructor Destroy;
    function GetProgress : Byte;
    function GetLastByte : Byte;
  end;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Label1: TLabel;
    Label2: TLabel;
    Button1: TButton;
    Label9: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    PingThread1 : TPingThread;
  end;

var
  Form1: TForm1;
Quote

 

Definition of constructor, destructor and Execute procedure:

constructor TPingThread.Create(AOwner : TComponent; OwnIP : in_addr; FromIP : Byte; ToIP : Byte);
begin
  inherited Create(false); // <-- Access violation happens here
  LocOwnIP := OwnIP;
  LocFromIP := FromIP;
  LocToIP := ToIP;
  LocOwner := AOwner;
end;

destructor TPingThread.Destroy;
begin
  AddressList.Free;
  inherited Destroy;
end;

procedure TPingThread.Execute;
var
  IPAddressRec : in_addr;
  i : Byte;
  TempInt : Integer;
  PingResult : Integer;
begin
  AddressList := TStringList.Create;
  AddressList.Clear;
  Ping1 := TPing.Create(LocOwner);
  for i := LocFromIP to LocToIP do
  begin
    IPAddressRec.S_un_b.s_b4 := i;
    if (IPAddressRec.S_addr <> LocOwnIP.S_addr) then
    begin
      LastByte := i;
      if (LocFromIP < LocToIP) then Progress := ((i - LocFromIP) * 100) DIV (LocToIP - LocFromIP);
      Ping1.Address := inet_ntoa(IPAddressRec);
      PingResult := Ping1.Ping;
      if (PingResult <> 0) then AddressList.Add(Ping1.Address);
    end;
  end;
end;

The thread is created in a button click event:

procedure TForm1.Button1Click(Sender: TObject);
var
  DelayVal : TDateTime;
  Handle1 : THandle;
  OwnIP : in_addr;
  TempStr : string;
begin
  // blah-blah...
  PingThread1.Create(Form1, OwnIP, 1, 31);
  Handle1 := PingThread1.Handle;
  while ((PingThread1 <> nil) and (WaitForSingleObject(Handle1, 0) <> WAIT_OBJECT_0)) do
  // blah-blah
  PingThread1.Destroy;
end;

As soon as TPingThread hits its first line of code, I get an access violation. It doesn't matter if it is the "inherited Create" line that comes first, or if I rearrange it like this:

constructor TPingThread.Create(AOwner : TComponent; OwnIP : in_addr; FromIP : Byte; ToIP : Byte);
begin
  LocOwnIP := OwnIP; // <-- Access violation happens here
  LocFromIP := FromIP;
  LocToIP := ToIP;
  LocOwner := AOwner;
  inherited Create(false);
end;

In the first example, I get the access violation on the "Inherited Create" line. In the second example, I get it on the LocOwnIP := OwnIP line.

 

I don't understand why. I thought that the variables defined in the thread's private section was accessible to all parts of the thread. Also, I think that it looks very much like the examples I've used.

Am I missing something here?

Share this post


Link to post
 PingThread1 := TPingThread.Create(Form1, OwnIP,1,31);

you also have a leak because you don't release Ping1.

And I also think you're blocking the main thread, so you might as well not use a thread.

Share this post


Link to post
3 minutes ago, Christophe E. said:

 PingThread1 := TPingThread.Create(Form1, OwnIP,1,31);

you also have a leak because you don't release Ping1.

And I also think you're blocking the main thread, so you might as well not use a thread.

Oh, crap. This is so obvious. I've stared myselft blind at that. Thanks!

 

True. I need to destroy Ping1 when done. Well spotted.

About blocking: This is an example, just to get the thread to work. In the final version, there is supposed to be a number of threads, and the main thread will not be blocked.

Share this post


Link to post
20 hours ago, ErikT said:

 


type
  TPingThread = class(TThread)
  private
...
  public
    constructor Create(AOwner : TComponent; OwnIP : in_addr; FromIP : Byte; ToIP : Byte); reintroduce;
    destructor Destroy; override; // <---- Add override to the destructor

 

 

Share this post


Link to post

On a side note, you should not be passing an Owner to your thread. You are creating the TPing object inside your worker thread, so don't assign a component from the main thread as its Owner. Set the Owner to nil instead, and then Free() the object when you are done using it.

  • Like 2

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×