Восстановление изображений в потоке - PullRequest
2 голосов
/ 08 октября 2009

Я пытаюсь заставить программу получения изображений работать со списком.

Список содержит элементы типа (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 ]

4 голосов
/ 08 октября 2009

Есть много способов решить эту проблему, вот два примера:

  • Не используйте список объектов, используйте 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() в основном опрашивает. Не много накладных расходов, но все еще плохой стиль.

3 голосов
/ 08 октября 2009

Основная проблема в том, что ваш код не защищает сам цикл с помощью мьютекса. Как вы, вероятно, поняли, это создаст огромный мьютекс, который значительно замедлит работу системы.

Вот хорошее решение:

  • Заменить цикл 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;

Добавьте необходимый код мьютекса, операторы try и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...