【问题标题】:merge paint results in thread bitmap painting在线程位图绘制中合并绘制结果
【发布时间】:2014-08-14 18:38:04
【问题描述】:

我想加快绘制位图的速度,因此我设计了一个类似BITMAP THREAD CLASS 的类。完成部分图像的单独绘制后,我想在 Thread.done 过程中合并所有图像 我的代码是这样的

    type
      TbmpthreadForm = class(TForm)
        .....
        THreadImage: TImage;
        procedure Button_threadstartClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Private-Deklarationen }
        procedure ThreadDone(Sender: TObject);
      public
        { Public-Deklarationen }
        fserver, fdatabasename, ftablename: String;
        global_thread_counter: Integer;
        XPixel, YPixel: Integer;
        Masterbitmap: TBitmap;
      end;

    var
      bmpthreadForm: TbmpthreadForm;

    implementation

    {$R *.dfm}

    procedure TbmpthreadForm.ThreadDone(Sender: TObject);
    begin
      dec(global_thread_counter);
      MyStatusBar.SimpleText := 'Thread Count ->' + IntToStr(global_thread_counter);

      Masterbitmap.Canvas.Lock;
      with (Sender as TPaintBitmapThread) do
      begin
        bitblt(Masterbitmap.Canvas.handle, 0, 0, XPixel, YPixel,
          bitmap.Canvas.handle, 0, 0, srcand);
        THreadImage.Picture.Bitmap.Assign(Masterbitmap);
        // lets see local tthread intermediate results  and save it to HD
        THreadImage.Picture.Bitmap.SaveToFile('c:\temp\myimage' + IntToStr(Index)
  + '.bmp');
      end;
      Masterbitmap.Canvas.UnLock;

      if (global_thread_counter = 0) then
      begin
         ...
      end;
    end;
procedure TbmpthreadForm.Button_threadstartClick(Sender: TObject);
var
     ..... 
begin

  index_max := 2000000;
  threadCounter := 10;
  Indexdelta := round(index_max / threadCounter);

  ///
  ///
  ....
  Masterbitmap.Width := XPixel;
  Masterbitmap.Height := YPixel;

  for i := 0 to threadCounter - 1 do
  begin
    n := i * Indexdelta;
    m := (i + 1) * Indexdelta;
    //  just a test sql string .... 
    sqlstr := 'select * from  Mytable  where objectindex <' + IntToStr(m) +
      ' and Objectindex >' + IntToStr(n);

    aPaintBitmapThread := TPaintBitmapThread.Create(XPixel, YPixel, ......   , fserver, fdatabasename, ftablename,
      sqlstr, i);
    aPaintBitmapThread.OnTerminate := ThreadDone;
    Memo1.Lines.Add('start thread->' + IntToStr(i));
    inc(global_thread_counter);
  end;

end;

Thread.done 设计遵循 SO (reference question 由于生成的图像/ Masterbitmap 看起来与 run 到 run 有点不同,我想我的方法不是线程安全设计,用于将 Thread bmp 内容复制到 VCL mainform 中的 masterbitmap 中, 我在我的代码中看不到任何错误,有什么问题????

补充问题

Q1:TPaintBitmapThread 中的 fbitmap 是在 Thread.create 过程中创建的,对于 TAdoconnection,我找到了注释,它应该在 thread.execute 中创建。位图也必须这样做吗?

Q2 : 附件图片显示了一个线程的图像(位图)的预期结果和实际的图像结果(如 THreadImage.Picture.Bitmap.SaveToFile 命令所见)

【问题讨论】:

  • 告诉我们更多关于 XPixel 和 YPixel 的信息。为什么我们不能有一个完整的程序?
  • 完整的代码很长; Xpixel 和 ypixel 是线程内位图的大小,我对主位图也使用相同的大小。使用我的 bitblt 命令,我只需将本地线程 bmp 复制到主 bmp
  • 我不想看到你的完整代码。我想看一个完整的程序来说明这个问题。一个 SSCCE。
  • SSCCE 很难创建;可能与 q1 我可以获得更多帮助或额外的奇怪调试结果,从单个线程保存的位图也显示完整的数据/图像。 (它应该只包含一定数量的图纸);我在上面的源代码中添加了调试行
  • 还有一点:在位图 Delphi 中绘制异步线程,Remy Lebeau 的回答;关键部分是否也需要?我是否正确理解了这里的解决方案?

标签: multithreading delphi bitmap


【解决方案1】:
    bitblt(Masterbitmap.Canvas.handle, 0, 0, XPixel, YPixel,
      bitmap.Canvas.handle, 0, 0, srcand);

您明确调用了 Masterbitmap.Canvas.Lock,但是您没有调用 bitmap.Canvas.Lock(因此您可以在此调用中随时松开画布句柄...)

此外,您需要考虑 GDI 本身内的线程安全性:应不惜一切代价避免在不同线程之间共享任何 GDI 对象。例如,如果您同时将位图选择到两个不同的设备上下文中(但在不同的线程中),您可能会在 GDI 本身中遇到问题...

请注意,旧版本的 delphi 不能防止共享缓存句柄(字体、画笔和钢笔句柄缓存在全局列表中。如果我没记错的话,这已在 XE3 服务包中修复)。

简而言之:如果您真的需要多线程,我会考虑完全避免使用 TCanvas 和 TBitmap。 (这样更容易实现多线程安全)

【讨论】:

  • 字体、画笔和钢笔句柄缓存在一个全局列表中。 -> 这似乎是一个很好的输入,即使 XE5 也显示相同的错误行为。 (见更新的问题)
  • 猜猜这是我问题的真正根本原因“请注意,旧版本的 delphi 不能防止共享缓存句柄(字体、画笔和钢笔句柄缓存在全局列表中。如果我没记错的话,这是在 XE3 服务包中修复的)。”
猜你喜欢
  • 1970-01-01
  • 2013-03-17
  • 1970-01-01
  • 1970-01-01
  • 2022-10-13
  • 2020-03-24
  • 1970-01-01
  • 2014-04-11
  • 2016-07-21
相关资源
最近更新 更多