线程中的图像检索器

时间:2009-10-07 21:27:45

标签: delphi streaming multithreading

我正在尝试使用图像检索器来处理列表。

该列表包含类型(TItem)的项目。 TItem有一些属性,如title,image和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;

不幸的是,它在一种情况下不起作用:清除列表并且线程正在检索项目的图像。

(所有读写项目均由互斥锁保护。)

我该怎么办?

谢谢:)

2 个答案:

答案 0 :(得分: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;

您甚至可以将图片网址本身用作句柄。

请注意,如果列表为空,则更好的方法是阻止线程,Sleep()调用基本上是轮询。没有多少开销,但仍然是糟糕的风格。

答案 1 :(得分:3)

基本问题是您的代码不使用互斥锁来保护循环本身。正如您可能已经意识到的那样,这会产生巨大的互斥量,从而显着降低系统速度。

这是一个很好的解决方案:

  • 用while循环替换for循环
  • 创建用于查找下一个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;

自己添加必要的互斥代码,try-statements等。