合并绘制结果在线程位图绘制

时间:2014-06-24 13:15:37

标签: multithreading delphi bitmap

我想加快绘制位图,因此我设计了一个像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看起来与运行运行有点不同,我想我的方法不是线程安全设计,用于复制Thread bmp内容到VCL mainform中的masterbitmap, 我在代码中看不到任何错误,有什么问题????

其他问题

Q1:TPaintBitmapThread里面的fbitmap是在Thread.create程序里面创建的,对于TAdoconnection我找到了注释,它应该在thread.execute里面创建。这也必须在位图上完成吗?

Q2:附加图像显示了线程的图像(位图)的预期结果和实际图像结果(由example of the painting error THreadImage.Picture.Bitmap.SaveToFile命令看到)

1 个答案:

答案 0 :(得分: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。 (以这种方式安全多线程要容易得多)