Cancel a TThread in middle of execution!

Ok, I got a little problem. I do work on an application which is going to download different stuff from the internet, and I got a little problem with the threads. I use some classes that can use up to 5 seconds to complete (like Connect), and it all runs after eachother (not a big loop for the entire thread, but a task, start to end). Therefore I can't use the easy, classic, Cancel := True, if cancel = True then Exit; way. I did try most procedures in TThread to cancel it, like Terminate, DoTerminate, Suspend, etc..., but none of them seems to cancel it. Is there some not too hard way to simply terminate/cancel, and then free the Thread without having to add extra If Cancel = True ..... code in the Execute procedure (I can't do that, because it doesn't run in a loop, and some of the procedures inside that thread takes time to do, and I can't do that If Cancel = True between each line of code). 400 points for this working answer.

Another extra question, worth 100 points, what is the difference between Destroy, and Free when I free a component, or class (like TMemoryStream)? Which of them frees it fully (returns just as many bytes as it took when I created it)?
imnotaproAsked:
Who is Participating?
 
ceoworksConnect With a Mentor Commented:
Sorry I'm not sure and i don't have time to try this example but you can design your thread class like this :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

type
  TForm1 = class(TForm)
    IdTCPClient1: TIdTCPClient;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyThread = class(TThread)
  private
    FSocks: array[0..2] of TIdTCPClient;
  protected
    procedure Execute;
  public
    constructor Create(ConnIP: string; ConnPort);
    procedure StopConnections;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin

end;

{ TMyThread }

constructor TMyThread.Create(ConnIP: string; ConnPort);
var
  i: integer;
begin
  for i := 0 to 2 do
  begin
    FSocks[i] := TIdTCPClient.Create(nil);
    FSocks[i].Host := ConnIP;
    FSocks[i].Port := 381;
    FSocks[i].Connect;
  end;
  inherited Create(True);
  FreeOnTerminate := True;
end;

procedure TMyThread.Execute;
begin
  // internet stuff here
  Terminate;
end;

procedure TMyThread.StopConnections;
var
  i: integer;
begin
  Suspend;
  for i := 0 to 2 do
  begin
    FSocks[i].Disconnect;
    FreeAndNil(FSocks[i]);
  end;
  Terminate;
end;

end.

For to stop your connections with this class, all you need to do is calling StopConnections. Then after to close all the connections, thread will terminate itself.

I hope these helps..

Cheers,

Oktay Sancak
0
 
ceoworksConnect With a Mentor Commented:
Free method is doing the same work with Destroy but there is a little difference :

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

Free method is a procedure of TObject class. When you use TObject.Free, first of all it checks if this object nil or not then if it's not nil, it destroys the component. This protects you from to destroy a destroyed component and escape you from an error. This is the reason why Borland suggest you to use Free instead of Destroy. Because it's more secure.

When you free an object, it's not means that nil assigned to it. So most of the programmers using FreeAndNil(var Object) procedure, which has this code inside it :

procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;

Take a look at this, first of all 'nil' assigned to the object and then this object frees.

Cheers,

Oktay
0
 
ceoworksCommented:
I'm not sure if i completely understand your question but you may think to use this code :

MyThread.FreeOnTerminate := True;
..
MyThread.Suspend;
MyThread.Terminate;
..
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

 
imnotaproAuthor Commented:
Ceoworks: Thanks for this nice answer. I'll accept your answer (guarantied) when I get the other answer (it's not possible to accept one at time).

Ceoworks again: Okay, I'll try that now.
0
 
ceoworksCommented:
Ohh i understand what you meant when you say that stop execution of internet related things and free them. In 5 min, i'll go back to home and if i'll have time i'll try to develop a little sample for you.

Cheers,

Oktay
0
 
imnotaproAuthor Commented:
Okay, with the first question I need a bit more help. Take a look at this:

procedure Tdownloader.Execute;
begin
  ...
  //Here we get some instance where this download fails, and therefore I want it to kill itself, and free completly
  //The ID variable is declared in the Type, and contains (100% sure) it's own number in it's array of Tdownloader.
  KillDownloadHandle(ID);
  ...
end;

procedure KillDownloadHandle(ID: Integer);
begin
  //Here I tried what you suggested:
  download[ID].Suspend;

  freeandnil(download[ID]);
end;


I think that part is a bit dumb, cuz when the thread is going to kill itself, I just proved that it stops on Suspend, which again causes that it never runs freeandnil. Will FreeOnTerminate make sure it gets freed then? Or should I do something like this:

procedure KillDownloadHandle(ID: Integer; Myself: Boolean);
begin
  if myself=True then
  begin
    exit;   //Simply let FreeOnTerminate free it
  end else begin
    download[ID].Suspend;
    freeandnil(download[ID]);
  end;
end;


Would that make that part memoryleakfree (I know it frees the entire application automatically on exit, but this application can run LONG without being closed, so everything should be leak-free)?
0
 
imnotaproAuthor Commented:
Okay, that helped a lot :). One more thing, what's the difference between Suspend and Terminate here?

The points are yours :).
0
 
ceoworksCommented:
Before i see your last post, i had send this answer. I can give you a detailed answer after 1-2 hour because i'm ready to go back to home now. Until that time, you may wants to try the logic of my last code.. Sorry but I really hurry and i don't have time to think about your last code. I'll try to make it all clear for you then.

Cheers,

Oktay

0
 
ceoworksCommented:
Suspend stops the execution of your thread then it become safe for you to Disconnect and FreeAndNil your sockets. At the final you are calling Terminate and then your thread frees itself.

I'm glad to hear that you problem solved :)

Have a nice day,

Oktay Sancak
0
 
ceoworksCommented:
Sorry i was hurried when i was typing this code so it needs a little fix :

  TMyThread = class(TThread)
  private
    FSocks: array[0..2] of TIdTCPClient;
  protected
    procedure Execute;
  public
    constructor Create(ConnIP: string; ConnPort);
    procedure StopConnections;
  end;
 
  should be :

  TMyThread = class(TThread)
  private
    FSocks: array[0..2] of TIdTCPClient;
    procedure Execute; override; // override
  public
    constructor Create(ConnIP: string; ConnPort: integer); // and type of ConnPort
    procedure StopConnections;
  end;

Rgds,

Oktay
0
 
imnotaproAuthor Commented:
Thanks, you've really been helpful, you deserve those 500 points :).

I got a system very similar to yours with a few modifications (to suit my previous setup), and it's all working now, 100% failsafe. Thanks :).
0
 
ceoworksCommented:
To be helpfull is more important than points. I'm really glad to hear that your problem solved.. :)

Have a nice day,

Oktay Sancak
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.