Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 这个代码是线程安全的吗_Multithreading_Delphi_Thread Safety_Vcl - Fatal编程技术网

Multithreading 这个代码是线程安全的吗

Multithreading 这个代码是线程安全的吗,multithreading,delphi,thread-safety,vcl,Multithreading,Delphi,Thread Safety,Vcl,已编辑 // 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 A

已编辑

// 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;
这似乎完全解决了绘图问题!显然,在使用Draw或StretchDraw时必须锁定和解锁画布,因为在线程中,由于graphics.pas中的GDI对象缓存机制,其Bitmap.canvas的DC有时会被清除

请参见

否,因为:

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;

您只能从主VCL线程使用VCL控件。

一般来说,VCL代码不是线程安全的,这适用于大多数可供使用的VCL对象

你说:

这似乎是线程安全的,因为线程中没有生成异常,但图像似乎部分空白或绘制不正确

“无例外”并不表示“线程安全”。这和说“我开车上班,没有撞车,所以我的车是防撞车的”是一样的

线程问题高度依赖于时间,并以多种方式表现出来——不仅仅是例外。需要记住的重要一点是,线程问题可以作为潜在缺陷存在数月,直到出现任何异常情况。即便如此,它们通常很难以任何一致性度量进行复制

  • 实际上,如果线程问题出现异常,那么您就很幸运了,其他问题可能更难跟踪,甚至意识到它们正在发生
  • 你可以得到死锁,但如果它在后台线程中,你甚至可能没有意识到
  • 不正确的行为(如您所报告的),通常是由于以下比赛条件造成的:
    • 某些代码会在对象处于不一致状态时与对象交互,通常会导致高度不可预测的行为
    • 数据被错误地“丢弃”,因为一个例程的更改会立即覆盖另一个例程
  • 表现不佳;是的,实施不当的多线程解决方案会严重降低性能
当你说“图像似乎部分空白或绘制不正确”时,一个重要的问题是:是否总是相同的图像以相同的方式出现错误?如果是这样的话,那么问题可能只是您用于加载图像的控件与这些特定文件有问题

你真的在运行多个线程吗?我在您的代码中没有看到任何指示。
您是否尝试运行单线程以确认它是否真的是线程问题


编辑
那么最简单的解决方案可能是:

  • 定义可在其上实现消息处理程序的自定义消息常量
  • 为消息实现一个消息处理程序
  • 修改现有的
    过程TFormMain.MyThumbnailProvider
    ,以便它可以与VCL主线程同步,并将工作传递给同步处理程序
下面将调用VCL主线程中的自定义处理程序,并等待返回

Image1.Picture.LoadFromFile( Path );
/// [...]
Bitmap.Canvas.StretchDraw( ARect, Image1.Picture.Graphic );
声明记录类型。非常简单,但你也需要指针

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;
实现消息处理程序

type
  PThumbnailData = ^TThumbnailData;
  TThumbnailData = record
    FPath: Unicodestring;
    FWidth, FHeight: Integer;
    FBitmap: TBitmap;
  end;
procedure MSGThumbnailInfo(var Message: TMessage); message MSG_THUMBNAILINFO;

但是,如果他创建了一个新的
TPicture
对象供线程使用,他可以使用它来加载文件,而不是
TImage
控件提供的文件,这会起作用,对吗?是的,TPicture对象似乎是线程安全的,但在一个包含12个wmf文件的文件夹中,3个不正确?请看屏幕截图。当你说“图像似乎部分空白或未正确绘制”时,一个重要的问题是:是否总是相同的图像以相同的方式出现错误?”当你说“图像似乎部分空白或未正确绘制”时,一个重要的问题是:是否总是相同的图像以相同的方式出现错误?“不。。。每次选择文件夹时,都无法正确绘制不同的缩略图。有时,几乎所有的缩略图都正确绘制,而在其他时间,一组不同的缩略图绘制错误。是,多个线程正在运行。您没有看到代码的原因是代码位于JamShellBrowser中,我无法共享。如何定义TThumbnailData并编写消息?我们发现Bitmap.Canvas.StretchDraw(ARect,apiture.Graphic);可能是导致问题的原因。Bitmap.Canvas.StretchDraw是否线程安全?请参阅最新编辑。使用Canvas.Lock和Canvas.Unlock解决了问题。@比尔:是的,您注意到的问题可能已经解决了,但正如前面所指出的,这并不意味着不再存在线程问题。为此,您必须仔细检查正在调用的代码。例如,
APicture:=TPicture.Create
查看
TPicture.Create
的实现,此调用可以执行两个全局对象的延迟初始化。如果第一次调用同时来自多个线程,则可能会出现小内存泄漏。幸运的是,这还不算太糟糕,但是在这条线和锁定画布的点之间的VCL中发生了很多事情。你问的是线程安全问题,但我在你的问题中没有看到并发线程。你为什么要担心线程安全?你听说过Jim Kueneman的吗?它在以浏览器的方式显示文件方面做得非常好,甚至可以处理缩略图视图.Rob。是的,我使用Jim Kueneman的VirtualShellTools库很多年了。在德尔福2009年或2010年之前,它做得非常好。从那时起,我就无法安装它,据我所知,它已经有一段时间没有更新了。甚至Jim的用户群在一年多的时间里也几乎没有任何活动。我想吉姆现在正忙于其他事情。。。Plasmatech似乎也停止了shell的开发,只剩下JamShellBrower作为唯一可行的vcl shell了。。。这是非常好的方式,有很好的支持,以及最近的更新。