2013-07-17 93 views
6

我要修改和改變線程一些可視化組件,正如你知道這是不是安全的這樣做。線程安全的德爾福

我的問題是如何編寫完全線程安全的代碼?這可能嗎?如果是的話可以請給我一個簡單的例子嗎?

我的代碼不是線程安全的:

type 
    tMyWorkerThread = class(TThread) 
     public 
     procedure Execute; override; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure tMyWorkerThread.Execute; 
begin 
    //codes 
    //working with visual components 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    TMyWorkerThread.Create(false); 
end; 

謝謝。

+2

查看[Synchronize](http://docwiki.embarcadero.com/Libraries/XE4/en/System.Classes.TThread.Synchronize) – bummi

+2

使用File-> New-> Other'菜單,選擇'Delphi Projects-> Delphi Files-> Thread Object',並讀取它創建的新單元頂部的*巨大註釋*。 –

+0

*我必須修改和更改一些虛擬組件* 虛擬組件或可視組件? 什麼樣的更新?進度條可以很容易地從主線程完成,而工作人員trreads只會報告他們的工作 - 這是在幾行代碼 –

回答

0

我的問題與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; 

解決了,謝謝大家對我的幫助。

+7

傷心的是,你會添加和接受你自己的答案,而不是其他答案之一,告訴你同樣的事情。真的打破了Stack Overflow的工作流程。 –

+0

@JerryDodge我的回答更好,更清晰。 – Sky

5

您應該只訪問VCL從主VCL線程對象。

一些閱讀方法(屬性獲得者)在其他線程中的工作 - 但你必須提前證明它閱讀特定德爾福構建的VCL源。或不使用它。

PS:Synchronize方法在主VCL線程中運行給定過程,如果主線程也被阻塞,則暫停調用者線程,這可能導致死鎖。

瞭解更多:(實際上使這個答案,列出一些鏈接)

+2

好的清單!馬丁哈維的「多線程 - 德爾福方式」也應該在那裏。在我看來,在最高的位置: - D不幸的是[原創](http://www.pergolesi.demon.co.uk/prog/threads/ToC.html)不再存在,但有幾個「緩存」副本around:[Thaddy's](http://thaddy.co.uk/threads/)和[http://web.archive.org/](http://web.archive.org/web/20060305174604/http:/ /www.pergolesi.demon.co.uk/prog/threads/ToC.html)是我所知道的。它也可以通過[Code Central](http://cc.embarcadero.com/item/14809)獲得。 –

+0

@MarjanVenema沒關係。你的鏈接是相當有價值的,因爲實際上我的這個列表只需5分鐘的谷歌搜索,你的鏈接需要事先知道。 –

+1

如果馬丁的優秀文章被URL爛掉了,我把它發佈在我的網站上: http://www.seti.net/engineering/threads/threads.php –

8

編寫線程安全的代碼在Delphi中涉及基礎護理,你必須在任何其他語言,這意味着應對競爭條件。當不同的線程訪問相同的數據競爭條件發生。處理這個問題的一個好方法是聲明TCriticalSection的一個實例,並將危險的代碼包裝在其中。

下面的代碼顯示了一個屬性的getter和setter,它通過hypotesis具有競爭條件。

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; 

通知使用(CriticalX)的TCriticalSection單個實例的序列化訪問數據成員FX

但是,對於Delphi,您有一個額外的考慮!VCL不是線程安全的,所以爲了避免VCL競爭條件,導致改變屏幕必須在主線程中運行的任何操作。你得到的是通過調用同步方法中這樣的代碼。考慮到上述類,你應該這樣做:

procedure TMyThread.ShowX; 
begin 
    Synchronize(SyncShowX); 
end; 

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

如果你有2010 德爾福或更高版本,有可能利用匿名方法更簡單的方法:

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

希望這有助於!

+0

你可以停止呼叫**臨界區** s - 甚至**在另一個帖子中的事件** - **互斥體**?如果你知道Mutex是什麼,它可能是一個混淆的來源,如果你不知道它,它就會理解你的代碼。 – mg30rg