2009-10-07 7 views
2

Je suis en train de faire un chien d'arrêt d'image pour travailler avec une liste.image chien d'arrêt dans un fil

La liste contient des éléments de type (TItem) par exemple. TItem possède des propriétés telles que title, image et imageURL.

Il y a un fil avec la liste qui analyse tous les éléments et essayer de récupérer l'image de chaque élément en utilisant le imageURL de chaque élément.

Le fil qui récupère l'image de chaque œuvre de l'article comme celui-ci:

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; 

Malheureusement, il ne fonctionne pas dans un cas: lorsque la liste est effacée et que l'image d'un élément est récupéré par le fil.

(Tous les articles en lecture et écriture est protégée par un mutex).

Que dois-je faire?

Merci :)

Répondre

3

Le problème de base est que votre code ne protège pas la boucle elle-même en utilisant un mutex. Comme vous l'avez probablement compris, cela ferait un énorme mutex qui ralentirait considérablement le système.

Voici une bonne solution:

  • Remplacer la boucle for avec une boucle while
  • Créer un code qui trouve l'URL suivante et mutex protéger ce code
  • Faire de la recherche d'images utiliser des variables qui ne se rapportent pas à la liste, de sorte qu'il n'a pas besoin de protection mutex.
  • Enregistrez l'image récupérée en recherchant l'index correct à l'aide de l'URL. Cette découverte et ce stockage doivent être protégés par mutex.

Quelque chose comme ceci:

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; 

Ajoutez le code mutex nécessaire, essayez-vous-même des déclarations etc..

+0

Merci! Cette solution fonctionne :) – Ariel32

4

Il présente, voici de nombreuses façons de résoudre deux exemples:

  • Ne pas utiliser une liste d'objets, utilisez un TInterfaceList ou une liste générique des interfaces. Créez une interface à partir des méthodes publiques de la classe d'élément. Le thread conservera une référence d'interface, ce qui maintiendra le nombre de références au-dessus de zéro et, par conséquent, l'instance d'objet qui implémente l'interface ne sera pas supprimée. L'accès à l'objet sera donc sûr.

  • Ne pas accéder directement à l'élément de votre fil, mais donner seulement une poignée d'élément opaque au fil. Initialement, le thread utilisera ce handle pour demander les données nécessaires pour récupérer l'image, et comme il verrouillera la liste, l'accès sera sécurisé. Lorsque l'image est récupérée, le thread utilisera de nouveau la poignée pour définir l'image sur l'élément dans une section de code verrouillée. Si l'élément n'est plus valide, le handle ne sera pas résolu en un élément, et l'image récupérée sera simplement supprimée. Vous n'avez qu'à vous assurer que les poignées ne sont pas réutilisées, par exemple l'index de la liste ou l'adresse de l'élément seraient toutes deux de mauvaises idées. Un nombre entier qui sera incrémenté pour chaque élément OTOH fonctionnerait bien.

Code simplifié pour la deuxième façon:

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; 

Vous pouvez même utiliser l'URL de l'image elle-même comme la poignée.

Notez que le meilleur moyen serait de bloquer le thread si la liste est vide, votre appel Sleep() est en train d'interroger. Pas beaucoup de frais généraux, mais toujours un mauvais style.

+0

Je ne suis pas très familier avec les interfaces dans Delphi ... J'essaie de ne pas les utiliser quand c'est possible car les interfaces dans Delphi sont souvent la cause de beaucoup de bugs! Si les interfaces dans Delphi pouvaient fonctionner comme Java ou C#! Quoi qu'il en soit, merci pour votre aide :) – Ariel32

+1

Interfaces dans Delphi ne sont pas la cause de beaucoup de bugs. Les programmeurs qui font de mauvaises choses avec les interfaces dans Delphi sont la cause des bogues. –

+0

Oui! Je veux plutôt dire qu'il est facile d'oublier quelque chose qui peut causer un bug avec l'interface dans Delphi. J'utilise déjà beaucoup d'interfaces dans mes applications Delphi (la plupart du temps c'est lié à des modèles de design). – Ariel32