Thread-safe in delphi

前端 未结 3 978
一向
一向 2020-12-03 09:19

I have to modify and change some visual components in a thread and as you know it\'s not safe to doing this.

My question is how to write a completely thread-

相关标签:
3条回答
  • 2020-12-03 09:33

    Writing a thread safe code in Delphi involves the basic care you would have in any other language, which means to deal with race conditions. A race condition happens when different threads access the same data. A good way to deal with that is to declare an instance of TCriticalSection and wrap the dangerous code in it.

    The code below shows a getter and a setter of a property that, by hypotesis, has a race condition.

    constructor TMyThread.Create;
    begin
      CriticalX := TCriticalSection.Create;
    end;
    
    destructor TMyThread.Destroy; override;
    begin
      FreeAndNil(CriticalX);
    end;
    
    function TMyThread.GetX: string;
    begin
      CriticalX.Enter;
      try
        Result := FX;
      finally
        CriticalX.Leave;
      end;
    end;
    
    procedure TMyThread.SetX(const value: string);
    begin
      CriticalX.Enter;
      try
        FX := Value;
      finally
        CriticalX.Leave;
      end;
    end;
    

    Notice the use of a single instance of TCriticalSection (CriticalX) to serialize the access to the data member FX.

    However, with Delphi you have an aditional consideration! VCL is not thread safe, so in order to avoid VCL race conditions, any operation that results in screen changing must run in the main thread. You get that by calling such a code inside a Synchronize method. Considering the class above, you should do something like this:

    procedure TMyThread.ShowX;
    begin
      Synchronize(SyncShowX);
    end;
    
    procedure TMyThread.SyncShowX;
    begin
      ShowMessage(IntToStr(FX));
    end;
    

    If you have Delphi 2010 or later, there is an easier way that makes use of anonymous methods:

    procedure TMyThread.ShowX;
    begin
      Synchronize(procedure begin
        ShowMessage(IntToStr(FX));
      end);
    end;
    

    I hope this helps!

    0 讨论(0)
  • 2020-12-03 09:42

    My problem solved with Synchronize!

    type
      tMyWorkerThread = class(TThread)
          public
             procedure Execute; override;
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure tMyWorkerThread.Execute;
    begin
    
      //codes that takes long time
      Synchronize(procedure begin
         //working with visual components
      end
      );
    
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      TMyWorkerThread.Create(false);
    end;
    

    Thank you all for helping me.

    0 讨论(0)
  • 2020-12-03 09:51

    You should only access VCL objects from main VCL thread.

    Some reading methods (property getters) do work from other threads in practice - but you have to prove it in advance reading VCL sources for the specific Delphi build. Or not use it.

    PS: Synchronize method runs given procedure in main VCL thread, pausing the caller thread, which may lead to a deadlock, if main thread was also blocked.

    Read more: (actually making this answer to list some links)

    • http://www.michael-puff.de/Programmierung/Delphi/Code-Snippets/VCLThreadDemo.shtml
    • http://www.drbob42.com/uk-bug/hood-04.htm
    • http://delphi.about.com/od/kbthread/a/thread-gui.htm
    • Is it better to use TThread's "Synchronize" or use Window Messages for IPC between main and child thread?
    • Delphi 6 : breakpoint triggered on non-VCL thread stops main thread repaints
    • http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devwin32/win32_mthreadusemainthread_xml.html
    • Simplifying VCL thread wrapper code
    • Update a VCL component from CreateAnonymousThread
    • http://thaddy.co.uk/threads/ - the mirror of "Multithreading - The Delphi Way" by Martin Harvey
    • http://otl.17slon.com/ - new Delphi approach to threading
    0 讨论(0)
提交回复
热议问题