zoukankan      html  css  js  c++  java
  • Correct thread terminate and destroy

    http://www.techques.com/question/1-3788743/Correct-thread-destroy

    Hello At my form I create TFrame at runtime.

    At this frame I create background thread with executes commands in endless loop.

    But when I destroy this frame I should destroy this thread. I try

    thread.Suspend;
    thread.Terminate;
    FreeAndNil(thread);

    but get AV and ThreadError. How should i destroy thread?

    Don't suspend the thread. The terminate method just set the Terminated property to true,

    and your Execute method is responsible to terminate the thread.

    If it is suspended, it will not get a chance to terminate.

    Another problem with the code above, is that it likely frees the thread

    before it has a change to terminate the normal way.

    You must make sure that thread exits it's execute method to terminate it properly.

    Code could be something like this:

    procedure TThread.Execute;
    begin
      while not Self.Terminated do
      begin
        //do something
      end;
    end;

    Call this when You want to destroy thread:

    thread.Terminate;
    thread.WaitFor;
    FreeAndNil(thread);

    It's not necessary to call `Terminate` and `WaitFor` from the outside,

    as the thread destructor will do it itself.

    It may be necessary though to call it from overwritten destructors,

    before any fields are freed, to make sure these are no longer used from the thread.

    It is sufficient to do thread.Terminate.

    But you will probably want to set thread.FreeOnTerminate := true when it is created.

    Of course, in the tight loop of your thread (that is, in Execute),

    you need to check if the thread has been requested to terminate

    (check the Terminated property).

    If you find that the thread has been requested to terminate,

    simply break from the loop and exit from Execute.

    thread.Terminate only sets FTerminated property to True. It doesn't destroy thread.

    I know. But every thread must check for that in its Execute method.

    I assume the OP is doing this.

    You should never call suspend on a tthread its not safe to do so and resume should only be used to start a thread that was created suspended.

    In Delphi 2010 the suspend and resume where depreciated and the method start was introduced to reinforce this.

    For a more complete explanation see this thread at Codegears forums.

    having said that there are 2 ways I will terminate and free a tthread.

    1: I Set FreeOnTerminate when the thread is created so I just call.

    Thread.Terminate;

    2: Free the thread explicitly, as I need to read a result from a public property before the thread is freed and after it has terminated.

    Thread.Terminate;
    Thread.WaitFor;
    //Do somthing like read a public property from thread object
    if Thread <> nil then FreeAndNil(Thread);

    In the main execute loop it may be a good idea to put some exception handling in.

    Or you may be left wondering why the thread appears to terminate its self.

    This may be causing the AV if the thread is set to FreeOnTerminate and it has already been freed when you try to free it.

    procedure TThread.Execute;
    begin
      while not Terminated do
      begin
        try
          //do something
        except
          on E:Exception do
           //handle the exception
        end;
      end;
    end; 

    Free a TThread either automatically or manually

    I have a main thread and a separate thread in my program.

    If the separate thread finishes before the main thread, it should free itself automatically.

    If the main thread finishes first, it should free the separate thread.

    I know about FreeOnTerminate, and I've read that you have to be careful using it.

    My question is, is the following code correct?

    procedure TMyThread.Execute;
    begin
      ... Do some processing
    
      Synchronize(ThreadFinished);
    
      if Terminated then exit;
    
      FreeOnTerminate := true;
    end;
    
    procedure TMyThread.ThreadFinished;
    begin
      MainForm.MyThreadReady := true;
    end;
    
    procedure TMainForm.Create;
    begin
      MyThreadReady := false;
    
      MyThread := TMyThread.Create(false);
    end;
    
    procedure TMainForm.Close;
    begin
      if not MyThreadReady then
      begin
        MyThread.Terminate;
        MyThread.WaitFor;
        MyThread.Free;
      end;
    end;

     Thanks!

    You can simplify this to:

    procedure TMyThread.Execute;
    begin
      // ... Do some processing
    end;
    
    procedure TMainForm.Create;
    begin
      MyThread := TMyThread.Create(false);
    end;
    
    procedure TMainForm.Close;
    begin
      if Assigned(MyThread) then
        MyThread.Terminate;
      MyThread.Free;
    end;

    Explanation:

    • Either use FreeOnTerminate or free the thread manually, but never do both.
      The asynchronous nature of the thread execution means that you run a risk of not freeing the thread
      or (much worse) doing it twice.

      There is no risk in keeping the thread object around after it has finished the execution,
      and there is no risk in calling Terminate() on a thread that has already finished either.

    • There is no need to synchronize access to a boolean that is only written from one thread and read from another.
      In the worst case you get the wrong value, but due to the asynchronous execution that is a spurious effect anyway.
      Synchronization is only necessary for data that can not be read or written to atomi

    How to terminate anonymous threads in Delphi on application close?

    http://www.techques.com/question/1-10401865/How-to-terminate-anonymous-threads-in-Delphi-on-application-close

    I have a Delphi application which spawns 6 anonymous threads upon some TTimer.OnTimer event.

    If I close the application from the X button in titlebar Access Violation at address $C0000005 is raised and FastMM reports leaked TAnonymousThread objects.

    Which is the best way to free anonymous threads in Delphi created within OnTimer event with TThread.CreateAnonymousThread() method?

    SOLUTION which worked for me:

    Created a wrapper of the anonymous threads which terminates them upon being Free-ed.

    type
      TAnonumousThreadPool = class sealed(TObject)
      strict private
        FThreadList: TThreadList;
        procedure TerminateRunningThreads;
        procedure AnonumousThreadTerminate(Sender: TObject);
      public
        destructor Destroy; override; final;
        procedure Start(const Procs: array of TProc);
      end;
    
    { TAnonumousThreadPool }
    
    procedure TAnonumousThreadPool.Start(const Procs: array of TProc);
    var
      T: TThread;
      n: Integer;
    begin
      TerminateRunningThreads;
    
      FThreadList := TThreadList.Create;
      FThreadList.Duplicates := TDuplicates.dupError;
    
      for n := Low(Procs) to High(Procs) do
      begin
        T := TThread.CreateAnonymousThread(Procs[n]);
        TThread.NameThreadForDebugging(AnsiString('Test thread N:' + IntToStr(n) + ' TID:'), T.ThreadID);
        T.OnTerminate := AnonumousThreadTerminate;
        T.FreeOnTerminate := true;
        FThreadList.LockList;
        try
          FThreadList.Add(T);
        finally
          FThreadList.UnlockList;
        end;
        T.Start;
      end;
    end;
    
    procedure TAnonumousThreadPool.AnonumousThreadTerminate(Sender: TObject);
    begin
      FThreadList.LockList;
      try
        FThreadList.Remove((Sender as TThread));
      finally
        FThreadList.UnlockList;
      end;
    end;
    
    procedure TAnonumousThreadPool.TerminateRunningThreads;
    var
      L: TList;
      T: TThread;
    begin
      if not Assigned(FThreadList) then
        Exit;
      L := FThreadList.LockList;
      try
        while L.Count > 0 do
        begin
          T := TThread(L[0]);
          T.OnTerminate := nil;
          L.Remove(L[0]);
          T.FreeOnTerminate := False;
          T.Terminate;
          T.Free;
        end;
      finally
        FThreadList.UnlockList;
      end;
      FThreadList.Free;
    end;
    
    destructor TAnonumousThreadPool.Destroy;
    begin
      TerminateRunningThreads;
      inherited;
    end;

     End here is how you can call it:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      FAnonymousThreadPool.Start([ // array of procedures to execute
        procedure{anonymous1}()
        var
          Http: THttpClient;
        begin
          Http := THttpClient.Create;
          try
            Http.CancelledCallback := function: Boolean
              begin
                Result := TThread.CurrentThread.CheckTerminated;
              end;
            Http.GetFile('http://mtgstudio.com/Screenshots/shot1.png', 'c:1.jpg');
          finally
            Http.Free;
          end;
        end,
    
        procedure{anonymous2}()
        var
          Http: THttpClient;
        begin
          Http := THttpClient.Create;
          try
            Http.CancelledCallback := function: Boolean
              begin
                Result := TThread.CurrentThread.CheckTerminated;
              end;
            Http.GetFile('http://mtgstudio.com/Screenshots/shot2.png', 'c:2.jpg');
          finally
            Http.Free;
          end;
        end
      ]);
    end;

    No memory leaks, proper shutdown and easy to use.

    If you want to maintain and exert control over your threads' lifetimes then you should not use anonymous threads.

    Maintain a list of TThread instances and free them at shutdown time.

    Whilst it is possible to do what you want with anonymous threads,

    it's a lot of extra work that brings no real benefits.

    I see.

    But I still do not get it.

    TAnonymousThread is a descendant of TThread.

    So I can maintain a list of them and try to terminate them (since the RTL does not do it automatically).

    When I try to terminate it says:

    Project mtgstudio.exe raised exception class EThread with message 'Thread Error: The handle is invalid (6)'.

    Read the docs for the anonymous thread.

    You are not allowed to hold a reference to the TThread since it uses FreeOnTerminate.

    System.Classes.TThread.CreateAnonymousThread 

    Creates an instance of an internally derived thread.

    CreateAnonymousThread creates an instance of an internally derived TThread that simply will call the anonymous method of typeTProc.

    This thread is created as suspended, so you should call the Start method to make the thread run.

    The thread is also marked as FreeOnTerminate, so you should not touch the returned instance after calling Start.

    It is possible that the instance had run and then has been freed before other external calls or operations on the instance were attempted.

    type TProc = reference to procedure;
    type TProc = reference to procedure(Arg1: T);
    type TProc = reference to procedure(Arg1: T1, Arg2: T2);
    type TProc = reference to procedure(Arg1: T1, Arg2: T2, Arg3: T3);
    type TProc = reference to procedure(Arg1: T1, Arg2: T2, Arg3: T3, Arg4: T4);

    TProc declares a reference to a generic procedure.

    Use the TProc type as a reference to a generic procedure.

    There are a few variants of TProc type, each accepting a different number of generic arguments.

  • 相关阅读:
    纯手工打造漂亮的瀑布流,五大插件一个都不少Bootstrap+jQuery+Masonry+imagesLoaded+Lightbox!
    纯手工打造漂亮的垂直时间轴,使用最简单的HTML+CSS+JQUERY完成100个版本更新记录的华丽转身!
    FineUI v3.3.1 发布了!
    FineUI参考手册(离线版)现已免费提供下载!
    #CSDN刷票门# 有没有人在恶意刷票?CSDN请告诉我!用24小时监控数据说话!
    FineUI有三篇文章同时上博客园首页10天内推荐排行,难得啊!
    记 FineUI 官方论坛所遭受的一次真实网络攻击!做一个像 ice 有道德的黑客!
    如何优化 FineUI 控件库的性能,减少 80% 的数据上传量!
    我在 CSDN 的小窝
    2017年IT行业测试调查报告
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4016461.html
Copyright © 2011-2022 走看看