2009-10-07 24 views
2

我試圖使圖像檢索器與列表一起工作。圖像檢索器中的線程

該列表包含例如類型(TItem)的項目。 TItem有一些屬性,如標題,圖像和imageURL。

有一個列表中的線程掃描所有項目,並嘗試通過使用每個項目的imageURL檢索每個項目的圖像。

是檢索每個項目的工作像這樣的形象螺紋:

while not terminated do 
begin 
for i := 0 to List.count-1 do 
begin 
    item := List.Items[i]; 
    //Note : it can takes a few sec to retrieve the image from the imageURL. This method 
    //retrieve the image from the item.imageURL and then assign it to item.image 
    RetrieveImage(item.imageURL, item.Image); 
end; 
sleep(100); 
end; 

不幸的是,它並沒有在一種情況下工作:當列表被清除,該項目的圖像被檢索由線程。

(所有項目的讀寫受互斥鎖保護)。

我該怎麼辦?

謝謝:)

回答

3

最基本的問題是你的代碼不能使用互斥體保護循環本身。正如你可能已經意識到的那樣,這會產生一個巨大的互斥體,顯着降低系統性能。

這裏是一個很好的解決方案:

  • 更換for循環與while循環
  • 創建找到下一個URL和代碼互斥保護的代碼
  • 使圖像檢索使用與列表無關的變量,以便它不需要互斥鎖保護。
  • 通過使用URL查找正確的索引來保存檢索到的圖像。這個發現和存儲必須受到互斥鎖保護。

事情是這樣的:

while not terminated do 
begin 
    currenturl:=''; 
    while true do begin 
    Mutex begin 
    currenturl:=FindNextUrl(currentUrl); 
    Mutex end 
    if currenturl='' then break; // No more URLs to be found 
    RetrieveImage(currenturl,image); 
    Mutex begin 
    index:=FindUrlIndex(currenturl) 
    List[index].image:=image; 
    Mutex end 
    end; 
    sleep(100); 
end; 

添加必要的互斥代碼,嘗試語句等自己。

+0

謝謝!此解決方案有效:) – Ariel32 2009-10-08 07:52:40

4

有很多方法來解決這個問題,這裏有兩個例子:

  • 不要使用對象的列表,使用的接口TInterfaceList或通用的清單。從項目類的公共方法創建一個接口。該線程將維護一個接口引用,保持引用計數大於零,因此實現該接口的對象實例不會被刪除。因此訪問該項目將是安全的。

  • 不要直接從您的線程訪問項目,但只給線程一個不透明的項目句柄。最初,線程將使用該句柄來請求獲取圖像所需的數據,並且由於它將鎖定列表,所以訪問是安全的。當檢索到圖像時,線程將再次使用手柄將圖像設置到代碼的鎖定部分中的項目。如果項目不再有效,句柄將不會解析爲項目,並且檢索到的圖像將被簡單地刪除。您只需確保句柄不被重新使用,例如列表索引或項目地址都是不好的想法。每個OTOH項目的整數將會增加。對於第二種方式

簡化代碼:

var 
    Img: TImage; 
    ImgHandle: TImageFromURLHandle; 
... 

Img := TImage.Create; 
try 
    while not Terminated do 
    begin 
    // GetNextImageURL() is thread-safe 
    while List.GetNextImageURL(ImgHandle, ImgURL) do begin 
     RetrieveImage(ImgURL, Img); 
     // SetImage() is thread-safe and will do nothing if the image item 
     // is no longer in the list (invalid handle) 
     List.SetImage(ImgHandle, Img); 
    end; 
    Sleep(100); 
    end; 
finally 
    Img.Free; 
end; 

你甚至可以使用圖像URL本身作爲手柄。

請注意,更好的方法是阻止線程,如果列表爲空,則您的Sleep()調用基本上是輪詢。沒有太多的開銷,但仍然不好的風格。

+0

我對Delphi的界面不是很熟悉......我儘量不要使用它們,因爲Delphi中的接口通常是很多錯誤的原因!如果Delphi中的接口可以像Java或C#一樣工作!無論如何,感謝您的幫助:) – Ariel32 2009-10-08 07:55:20

+1

Delphi中的接口並不是導致大量錯誤的原因。程序員在Delphi中使用接口來做錯誤的事情是導致錯誤的原因。 – 2009-10-08 12:34:36

+0

是的!我的意思是,很容易忘記一些可能導致Delphi中的接口錯誤的東西。我已經在我的delphi應用程序中使用了很多接口(大部分時間與設計模式有關)。 – Ariel32 2009-10-08 13:48:11