Delphi - timer inside thread generates AV

前端 未结 6 1995
忘掉有多难
忘掉有多难 2020-12-07 23:56

I have the following thread code which executes correct first time. After that from time to time I get an AV on the Execute method of the thread, e.g

6条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-08 00:19

    I would never use timer in a thread. Instead I would create a system event and wait for it in the thread's execution loop for a specified time with the WaitForSingleObject function. This function waits until the specified object (in this case the event) is in the signalled state or the time-out interval elapses.

    The principle is easy, you'll create the event in the non-signalled state and keep it in that state until the thread is going to be terminated. This will result the WaitForSingleObject function to timeout every time what blocks your thread execution loop for the time specified in the function call. Once you'll decide to terminate your thread you just set the thread's termination flag (on which you should ask as much as you can) and set that event to the signalled state what causes the WaitForSingleObject function to return immediately.

    Here is an example which simulates a thread timer (with 2 seconds interval = 2000ms used as a second parameter in WaitForSingleObject function calls):

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
      TTimerThread = class(TThread)
      private
        FTickEvent: THandle;
      protected
        procedure Execute; override;
      public
        constructor Create(CreateSuspended: Boolean);
        destructor Destroy; override;
        procedure FinishThreadExecution;
      end;
    
    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        FTimerThread: TTimerThread;
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      ReportMemoryLeaksOnShutdown := True;
      FTimerThread := TTimerThread.Create(False);
    end;
    
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      FTimerThread.FinishThreadExecution;
    end;
    
    { TTimerThread }
    
    constructor TTimerThread.Create(CreateSuspended: Boolean);
    begin
      inherited;
      FreeOnTerminate := True;
      FTickEvent := CreateEvent(nil, True, False, nil);
    end;
    
    destructor TTimerThread.Destroy;
    begin
      CloseHandle(FTickEvent);
      inherited;
    end;
    
    procedure TTimerThread.FinishThreadExecution;
    begin
      Terminate;
      SetEvent(FTickEvent);
    end;
    
    procedure TTimerThread.Execute;
    begin
      while not Terminated do
      begin
        if WaitForSingleObject(FTickEvent, 2000) = WAIT_TIMEOUT then
        begin
          Synchronize(procedure
            begin
              Form1.Tag := Form1.Tag + 1;
              Form1.Caption := IntToStr(Form1.Tag);
            end
          );
        end;
      end;
    end;
    
    end.
    

提交回复
热议问题