-1

Using Delphi-v5 and a component (TmFileScan -- thanks Mats) that runs in a thread and I want to be able to Terminate the thread gracefully. After a lot of searching and reading here, I have been able to Terminate it but I need an Event to handle some screen-clean up after an Abort.

In the Thread I have added

while not(Terminated) do // Iterating about a zillion times :)
  ...

Then in the app...

Button1Click...
begin
  SearchThread.Terminate;
end;

and it works nicely. I have the screen clean up in the existing OnReady event which is fired when the thread has completed normally. But it is never seen if the Thread was Terminated so I need to add an OnAbort event to the component.

Could someone please give me a code snippet for that event. There are Pause and Resume events in the Component but no Abort.

Thank you.

user2373289
  • 51
  • 1
  • 2
  • 5
  • possible duplicate of [How to kill a thread in delphi?](http://stackoverflow.com/questions/4044855/how-to-kill-a-thread-in-delphi) – Tony Hopkinson May 31 '13 at 21:15
  • You seem to have the idea right on how to terminate a thread. So what is your question? How to write your own event to be called upon registration of the Terminated flag? Your question is unclear. – Glenn1234 May 31 '13 at 21:38
  • To determine if your thread terminated normally or was forced, set tthread.retvalue in your execute in different ways. In the onterminate event, this value can be read. See also http://www.delphipages.com/forum/showthread.php?t=209703. – LU RD May 31 '13 at 21:45
  • @TonyHopkinson: Thanks but that's where I got the code from to do what I have done so far. I need a notify event that it was Terminated early. – user2373289 May 31 '13 at 22:28
  • @Glenn1234: As I just mentioned to Tony, I need some notification back to my program to tell me it was terminated early. I have several Listboxes that are disabled while the Search is going on and I need to enable them EITHER on normal excution which I have done in the component's OnReady even which gets fired at the normal-end, but the OnReady gets skipped with an early Termination. – user2373289 May 31 '13 at 22:32
  • @user2373289: You obviously have direct access to the source code of the component's worker thread, so you can easily patch it to make the `OnReady` event always get triggered regardless of the termination condition. If you need help doing that then please provide a link where you obtained the component from in the first place so the rest of us can see it for ourselves instead of trying to guess what it is doing. – Remy Lebeau Jun 01 '13 at 00:02
  • @user2373289: I updated my answer with exact modifications you can make to the component's code. – Remy Lebeau Jun 01 '13 at 00:22
  • This question really isn't appropriate for StackOverflow. "Here's the name of this component I'm using (thanks to the author, BTW), and here's what I want it to do. Can you Google that component, download it, review its source, and post some code I can use to modify it? Thanks." This isn't a code writing service. – Ken White Jun 01 '13 at 03:29
  • @user2373289 Now that I think about it, since setting the Terminated flag exits the thread gracefully regardless, couldn't you just reset your controls when the thread has come back? Most of the time if I do a fully autonomous thread, I create a OnCompleted event which is fired for this purpose in any event. – Glenn1234 Jun 01 '13 at 08:05

1 Answers1

3

The TThread class has an OnTerminate event available. It is triggered by the virtual TThread.DoTerminate() method, which is called after Execute() exits, regardless of whether Execute() exits normally or via an uncaught exception. I would suggest overriding DoTerminate() and have it trigger the OnAbort event if the Terminated property is True or the FatalException property is not nil, and to trigger the OnReady event otherwise.

Update: Assuming you are using this TmFileScan component, then I suggest you make the following modifications so the OnReady event is always triggered:

TSearchThread = class(TThread)
private
  ...
protected
  ...
  procedure DoTerminate; override; // <-- add this
public
  destructor Destroy; override; // <-- add this
end;

constructor TSearchThread.Create(Owner: TmFileScan; SubDir, Started: Boolean;
  FilePaths, Filter: TStrings; fOnFileFound: TOnFileFoundEvent;
  fOnReady: TOnReadyEvent);
begin
  inherited Create(true);
  ...
  ffList := TStringList.Create; // <-- add this
  ...
  Resume;
end;

// add this
destructor TSearchThread.Destroy;
begin
  ffList.Free;
  inherited Destroy;
end;

procedure TSearchThread.Execute;
var
  ...
begin // function FindFile
  // remove this
  {
  ffList:= TStringList.Create;
  try
    while not Terminated do
    begin
  }
      for q:= 0 to ffPaths.Count - 1 do
      begin
        if Terminated then Break; // <-- add this
        for n:= 0 to ffFilters.Count - 1 do
        begin
          if Terminated then Break; // <-- add this
          Spec:= ffFilters[n];
          RFindFile(BackSlashFix(ffPaths[q]));
        end;
      end;
  // remove this
  {
      Synchronize(Ready); // <-- remove this
      Terminate;
    end;
  finally
    ffList.Free;
  end;
  }
end;

// add this
procedure TSearchThread.DoTerminate;
begin
  Synchronize(Ready);
  inherited;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks, but I am not that smart. :) The component does not have an OnTerminate or DoTerminate event to hook straight into, so I am unsure how to write the code to do what you suggest. I have never dealt with Threads before and I am only using this one as it does what I need. I do not have the time to spend learning and understanding Threads. I have not used them in 15-years of programming and I can see no use for them in my normal work-line for the foreseeable future. That's why I asked for a code snippet. – user2373289 May 31 '13 at 22:26
  • If that `TmFileScan` component is a design time component, it cannot be a direct `TThread` class descendant but it has `TThread` class implemened internally, which in turn means that this answer is not for you. It would apply if you were working with a `TThread` class descendant. If it's a component with internal thread, you'd need to have that internal `TThread` class public, or that component would have directly some termination event published (or at least public to be more specific). – TLama May 31 '13 at 23:29
  • @TLama: This answer does apply, considering that he stated in his question that he has access to the actual thread, and has already made modifications to that thread's code. – Remy Lebeau May 31 '13 at 23:58