Delphi : How to create and use Thread locally?

后端 未结 3 1902
既然无缘
既然无缘 2021-02-10 15:03

My database is in a VPS and I should get some query from my tables

Because of getting query from server taking long time ( depending on Internet speed ! ) , I want to us

相关标签:
3条回答
  • 2021-02-10 15:28

    I think that using a thread this way isn't a good idea, but the answer is yes. You can do it.

    procedure LocalThread;
    var
      LThread: TCustomThread; //Your thread class
      LThreadResult: xxxxxxx//Your result type
    begin
      LThread := TCustomThread.Create(True);
      try
        //Assign your properties
    
        LThread.Start;
    
        //Option A: blocking
        LThread.WaitFor;
    
        //Option B: non blocking
        while not LThread.Finished do
        begin
          Sleep(xx);
          //Some progress here ??
        end;
    
        //Here query your thread for your result property
        LThreadResult := LThread.MyResultProperty;
      finally
        LThread.Free;
      end
    
      //Do next jobs with LThreadResult
    end;
    
    0 讨论(0)
  • 2021-02-10 15:32

    Yes you can do that.

    The way I would do it is to add an event-handler to your form.
    You'll have to link the event-handler in code, but that's not that difficult.

    Create a thread like so:

    TMyEventHandler = procedure(Sender: TObject) of object;
    
    type
      TMyThread = class(TThread)
      strict private
        FDoneEvent: TMyEvent;
        FDone: boolean;
        FQuery: TFDQuery;
        constructor Create(DoneEvent: TMyEventHandler; Query: TFDQuery);
        procedure Execute; override;
        function GetQuery: TFDQuery;
      public
        property Query read GetQuery;
      end;
    
      TForm1 = class(TForm)
        FDQuery1: TFDQuery;  //Do not connect the FDQuery1 to anything!
        DataSource1: TDataSource;
        DBGrid1: TDBGrid;
      private
        FOnThreadDone: TMyEventHandler;
        FMyThread: TMyThread;
        procedure DoThreadDone;
        procedure ThreadDone;
      public
        property OnThreadDone: TMyEventHandler read FOnThreadDone write FOnThreadDone;
      ....
    
    implementation
    
    constructor TMyThread.Create(DoneEvent: TMyEvent; Query: TFDQuery);
    begin
      inherited Create(true);
      FDoneEvent:= DoneEvent;
      FQuery:= Query;
      Start;
    end;
    
    procedure TMyThread.Execute;
    begin
      //Do whatever with the query
      //when done do:
      FDone:= true;
      Synchonize(Form1.DoThreadDone);
    end;
    
    function TMyThread.GetQuery: TFDQuery;
    begin
      if not Done then Result:= nil else Result:= FQuery;
    end;
    
    procedure TForm1.DoThreadDone;
    begin
      if Assigned(FOnThreadDone) then FOnThreadDone(Self);
    end;
    
    procedure TForm1.ThreadDone(Sender: TObject);
    begin
      ShowMessage('Query is done');
      //Now you can display the result of the query, by wiring it
      //to a dataset.
      MyDataSource1.Dataset:= FMyThread.Query;
      FMyThread.Free;
    end;
    
    procedure TForm1.StartTheQuery;
    begin
      OnThreadDone:= Self.ThreadDone;
      FMyThread:= TMyThread.Create(OnThreadDone, FDQuery1);
    end;
    

    Now the query will run in the background and signal your event handler when it is done. Meanwhile you can do all the mousing around and user interaction you want without having to worry. Note that you cannot use FDQuery1 at all whilst the thread is using it, and you cannot have FDQuery1 wired to a DataSource whilst it's the thread is running with it.
    Leave it unwired and wire it in the ThreadDone event handler as shown.

    0 讨论(0)
  • 2021-02-10 15:33

    What you describe is not the best use of a thread. The calling code is blocked until the thread is finished. That negates the use of running code in parallel at all. You could just perform the query directly instead:

    procedure Requery;
    var
      ...
    begin
      ...
      // run query
      // do next jobs with query
      ...
    end;
    

    That being said, since you are using XE6, you can create a "local" thread by using the TThread.CreateAnonymousThread() method, specifying an anonymous procedure that "captures" the variables you want it to work with, eg:

    procedure Requery;
    var
      Event: TEvent;
      H: THandle;
    begin
      Event := TEvent.Create;
      try
        TThread.CreateAnonymousThread(
          procedure
          begin
            try
              // run query in thread
            finally
              Event.SetEvent;
            end;
          end
        ).Start;
        H := Event.Handle;
        while MsgWaitForMultipleObjects(1, H, False, INFINITE, QS_ALLINPUT) = (WAIT_OBJECT_0+1) do
          Application.ProcessMessages;
      finally
        Event.Free;
      end;
    
      // Do next jobs with query
      ...
    end;
    

    Alternatively:

    procedure Requery;
    var
      Thread: TThread;
      H: THandle;
    begin
      Thread := TThread.CreateAnonymousThread(
        procedure
        begin
          // run query in thread
        end
      );
      try
        Thread.FreeOnTerminate := False;
        H := Thread.Handle;
        Thread.Start;
        while MsgWaitForMultipleObjects(1, H, False, INFINITE, QS_ALLINPUT) = (WAIT_OBJECT_0+1) do
          Application.ProcessMessages;
      finally
        Thread.Free;
      end;
    
      // Do next jobs with query
      ...
    end;
    

    However, threading is more useful when you let it run in the background while you do other things and then you act when the thread has finished its work. For example:

    procedure TMyForm.Requery;
    var
      Thread: TThread;
    begin
      Thread := TThread.CreateAnonymousThread(
        procedure
        begin
          // run query in thread
        end
      );
      Thread.OnTerminate := QueryFinished;
      Thread.Start;
    end;
    
    procedure TMyForm.QueryFinished(Sender: TObject);
    begin
      if TThread(Sender).FatalException <> nil then
      begin
        // something went wrong
        Exit;
      end;
      // Do next jobs with query
    end;
    
    0 讨论(0)
提交回复
热议问题