2014-06-24 6 views
-4

비트 맵을 페인팅 속도를 높이려는 것이므로 BITMAP THREAD CLASS과 같은 클래스를 디자인했습니다. 부분적인 이미지의 개별 회화가 완료되면 내 코드가 Thread.done 디자인 SO 여기에 이전 항목을 다음이병합 페인트 비트 맵 페인팅 결과

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; 

처럼 간다 나는 reference question 합니다 (Thread.done 절차의 모든 이미지를 병합 할 결과 이미지/Masterbitmap 실행을 실행에서 조금 달라 보이는 것처럼 내 접근 방식은 VCL mainform masterbitmap 복사 스레드 bmp 콘텐츠에 대한 스레드 안전 디자인이 아닌 것 같아 내 코드에서 어떤 오류를 볼 수 없습니다, 무엇입니까 잘못된 ????

추가 질문

Q1 : TPaintBitmapThread 내의 fbitmap은 Thread.create 프로 시저 내에서 TAdoconnection 용으로 작성되었습니다. 주석을 찾았으므로 thread.execute 내에 만들어야합니다. 이 또한 비트 맵을 완료해야합니까?

Q2는 다음 첨부 된 이미지 (example of the painting error하여 THreadImage.Picture.Bitmap.SaveToFile 명령 된 것과 같이)는 나사와 실제 이미지 결과에 의한 화상 (비트 맵)의 예상 된 결과

+0

XPixel 및 YPixel에 대해 자세히 알려주십시오. 왜 우리는 완전한 프로그램을 가질 수 없습니까? –

+0

완전한 코드는 꽤 길다. Xpixel 및 ypixel은 스레드 내의 비트 맵 크기이며 masterbitmap에도 같은 크기를 사용합니다. 내 bitblt comand와 함께 난 그냥 마스터 bmp로 로컬 스레드 bmp를 복사 – user1769184

+0

나는 완전한 코드를보고 싶지 않아요. 나는 그 문제를 보여주는 완전한 프로그램을보고 싶다. SSCCE. –

답변

1
bitblt(Masterbitmap.Canvas.handle, 0, 0, XPixel, YPixel, 
     bitmap.Canvas.handle, 0, 0, srcand); 

를 나타낸다 명시 적으로 Masterbitmap.Canvas.Lock이라고 불렀지 만 bitmap.Canvas.Lock을 호출하지 않았습니다 (이 호출 내에서 언제든지 캔버스 핸들을 풀 수 있습니다 ...)

또한 GDI 자체 내에서 스레드 안전성을 고려해야합니다 : 다른 스레드간에 GDI 개체를 공유하는 것은 피해야합니다. 예를 들어 비트 맵을 동시에 두 개의 서로 다른 장치 컨텍스트로 선택하면 (다른 스레드에서) GDI 자체에서 문제가 발생할 수 있습니다.

이전 버전의 델파이는 공유를 방지하지 못합니다 캐시 된 핸들 (글꼴, 브러시 및 펜 핸들이 전체 목록에 캐시되어 있습니다. 올바르게 기억하면 XE3 서비스 팩에서 수정되었습니다).

간단히 말해서 : 나는 정말로 멀티 스레딩이 필요한 경우 TCanvas와 TBitmap을 완전히 피할 것을 고려하고 있습니다. (그렇게하면 멀티 스레딩이 훨씬 쉬워집니다.)

+0

글꼴, 브러시 및 펜 핸들이 전체 목록에 캐시됩니다. -> 이것은 좋은 입력 인 것처럼 보입니다. 심지어 XE5도 같은 오류 동작을 보입니다. (업데이트 된 질문을 참조하십시오) – user1769184

+0

이것이 내 문제의 근본 원인이라고 생각하십시오 "이전 버전의 델파이는 캐시 된 핸들 (글꼴, 브러시 및 펜 핸들이 전체 목록 내에 캐시되지 않도록 보호하지 않습니다. 내가 정확히 기억한다면 XE3 서비스 팩에서 수정되었습니다. ") – user1769184