[英]Is this code thread safe
// experimental code
procedure TFormMain.MyThumbnailProvider( const Path: Unicodestring; Width,
Height: Integer; out Bitmap: TBitmap );
var
AExtension: string;
ARect: TRect;
begin
AExtension := LowerCase( ExtractFileExt( Path ) );
if AExtension = '.wmf' then
begin
ARect.Left := 0;
ARect.Top := 0;
ARect.Right := Width;
ARect.Bottom := Height;
Image1.Picture.LoadFromFile( Path ); // added at design time to form
Bitmap := TBitmap.Create;
Bitmap.Width := Width;
Bitmap.Height := Height;
Bitmap.Canvas.StretchDraw( ARect, Image1.Picture.Graphic );
end;
end;
编辑
procedure TFormMain.MyThumbnailProvider( const Path: Unicodestring; Width, Height: Integer; out Bitmap: TBitmap );
var
ARect: TRect;
APicture: TPicture;
AExtension: string;
begin
// experimental code
if FileExists( Path ) then
begin
AExtension := LowerCase( ExtractFileExt( Path ) );
if AExtension = '.wmf' then
begin
ARect.Left := 0;
ARect.Top := 0;
ARect.Right := Width;
ARect.Bottom := Height;
APicture := TPicture.Create;
try
APicture.LoadFromFile( Path );
Bitmap := TBitmap.Create;
Bitmap.SetSize( Width, Height );
Bitmap.IgnorePalette := True;
Bitmap.PixelFormat := pf24bit;
Bitmap.Transparent := False;
Bitmap.Canvas.Lock; **// New**
try
Bitmap.Canvas.StretchDraw( ARect, APicture.Graphic );
finally
Bitmap.Canvas.Unlock; **// New!**
end;
finally
APicture.Free;
end;
end;
end;
end;
这似乎完全解决了绘图问题! 显然你在使用Draw或StretchDraw时必须锁定和解锁画布,因为在一个线程中,由于graphics.pas中的GDI对象缓存机制,它的Bitmap.canvas的DC有时会被清除。
不,因为这个:
Image1.Picture.LoadFromFile( Path );
/// [...]
Bitmap.Canvas.StretchDraw( ARect, Image1.Picture.Graphic );
您只能使用主VCL线程中的VCL控件。
通常,VCL代码不是线程安全的,这适用于大多数可用的VCL对象。
你说:
这似乎是线程安全的,因为线程中没有产生异常,但图像似乎是部分空白或未正确绘制?
“没有例外”并不表示“线程安全”。 这就像说“我开车上班,并没有撞车,所以我的车是防撞车。”
线程问题高度依赖于时序,并以各种方式表现出来 - 而不仅仅是异常。 需要记住的重要一点是,在发生任何不幸事件之前,线程问题可能会作为潜在缺陷存在数月。 即便如此,它们通常很难以任何一致性度量再现。
当你说“图像似乎是部分空白或没有正确绘制”时,一个重要的问题是:它是否总是以相同的方式行为不正常的图像? 如果是这样,那么问题可能只是您用于加载图像的控件存在这些特定文件的问题。
你真的在运行多个线程吗? 我没有在你的代码中看到任何表明这样的东西。
您是否尝试过运行单线程来确认它是否真的是一个线程问题?
编辑
那么最简单的解决方案可能是:
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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.