Как правило, код VCL не является потокобезопасным, и это относится к большинству объектов VCL, доступных для использования.
Вы сказали:
Похоже, что это потокобезопасно, поскольку в потоке не создаются исключения, но изображения кажутся частично пустыми или отображаются неправильно?
«Нет исключений» не являются признаком «безопасности потока». Это то же самое, что сказать: «Я поехал на работу и не разбился, поэтому моя машина защищена от столкновений».
Проблемы с многопоточностью сильно зависят от времени и проявляются разными способами - не только в исключениях. Важно помнить, что проблемы с многопоточностью могут существовать как скрытые дефекты в течение нескольких месяцев, прежде чем произойдет что-то плохое. И даже в этом случае их, как правило, очень трудно воспроизвести с какой-либо степенью согласованности.
- На самом деле вам повезло, если вы получаете исключения из-за проблем с многопоточностью, другие проблемы могут быть сложнее отследить, или даже понять, что они возникают.
- Вы можете получить взаимоблокировки, но если это в фоновом потоке, вы можете даже не осознавать этого.
- Неверное поведение (как вы сообщаете), как правило, из-за условий гонки, в которых:
- Некоторый код будет взаимодействовать с объектом, пока он находится в несовместимом состоянии - обычно это приводит к крайне непредсказуемому поведению.
- Данные неправильно «отбрасываются», потому что одна подпрограмма изменяется немедленно, перезаписывая другую.
- плохая производительность; да, плохо реализованные многопоточные решения могут серьезно снизить производительность.
Когда вы говорите «изображения кажутся частично пустыми или неправильно рисуются», возникает важный вопрос: всегда ли одни и те же изображения плохо себя ведут, одинаково? Если это так, то проблема может заключаться в том, что элемент управления, используемый для загрузки изображений, имеет проблему с этими конкретными файлами.
Вы на самом деле запускаете несколько потоков? Я не увидел в вашем коде ничего, что бы указывало на это.
Вы пытались запустить однопоточный, чтобы убедиться, что это действительно проблема с многопоточностью?
EDIT
Тогда самое простое решение, вероятно, будет:
- Определите пользовательский констант сообщения, на котором вы можете реализовать обработчик сообщений.
- Реализация обработчика сообщений для сообщения
- Измените существующий
procedure TFormMain.MyThumbnailProvider
, чтобы он мог синхронизироваться с основным потоком VCL и передавал работу синхронизированному обработчику.
Следующие вызовут ваш пользовательский обработчик в главном потоке VCL и будут ждать возврата.
procedure TFormMain.MyThumbnailProvider( const Path: Unicodestring;
Width, Height: Integer; out Bitmap: TBitmap );
var
LThumnailData: TThumbnailData; //Assuming an appropriately defined record
begin
LThumbnailData.FPath := Path;
LThumbnailData.FWidth := Width;
LThumbnailData.FHeight := Height;
LThumbnailData.FBitmap := nil;
SendMessage(Self.Handle, <Your Message Const>, 0, Longint(@LThumbnailData));
Bitmap := LThumbnailData.FBitmap;
end;
EDIT2
Требуется больше образца кода:
Объявление сообщения const.
const
//Each distinct message must have its own unique ref number.
//It's recommended to start at WM_APP for custom numbers.
MSG_THUMBNAILINFO = WM_APP + 0;
Объявление типа записи. Действительно просто, но вам нужен указатель тоже.
type
PThumbnailData = ^TThumbnailData;
TThumbnailData = record
FPath: Unicodestring;
FWidth, FHeight: Integer;
FBitmap: TBitmap;
end;
Объявление обработчика сообщений.
procedure MSGThumbnailInfo(var Message: TMessage); message MSG_THUMBNAILINFO;
Реализация обработчика сообщений.
procedure TForm3.MSGThumbnailInfo(var Message: TMessage);
var
LThumbnailData: PThumbnailData;
begin
LThumbnailData := Pointer(Message.LParam);
//The rest of your code goes here.
//Don't forget to set LThumbnailData^.FBitmap before done.
Message.Result := 0;
inherited;
end;