Solved

Multithread update screen using directdraw -> DeadLock

Posted on 2007-04-05
5
979 Views
Last Modified: 2009-12-16
My app transfer images from server and display images to form!!

It works fine in my desktop(XP SP2, Intel Core2 CPU 6400@ 2.13GHz, 2.14GHz, 2GB RAM, NVIDIA GeForce 7950 GT)

But specific notebook(HP, XP SP2, Intel Core2 CPU T7400@ 2.13GHz, 2.16GHz, 1GB RAM, ATI Mobility Radeon X1600) was hanging after running about 3~5 minutes!!

I found where is problem by logging!! The problem `DrawChannelText()` method!!

I assume the problem is multi-thread update to screen!!

But I can not sure it, I try to synchronize by TCanvas.Lock/UnLock method!!

1. Connection Thread -> Fire DrawImageCallback for every frame image -> DrawChannelText() to draw text
2. Main Thread -> WM_TIMER for update screen every 50ms

I can not TThread.Synchronize to synchronize update screen. Because thread-callback was fired in dll.

I use TDisplay and TSurface classes to use directdraw (DDUtil.pas, http://www.clootie.ru/delphi/download_dx92.html)

Following DrawImageCallback() method fired by separated thread for connection.

There are many connections to display remote server screen.


procedure TMainForm.DrawImageCallback(Channel: PChannel; AVideoData: TVideoData);
var
  DstR, SrcR: TRect;
  hr: HRESULT;
  ddsd: TDDSURFACEDESC2;
  pDDS: IDIRECTDRAWSURFACE7;
  pDst: Pointer; // memory image buffer
begin
  Canvas.Lock;
  try
    pDDS := FChannelSurface.GetDDrawSurface;

    FillChar(ddsd, SizeOf(ddsd), 0);
    ddsd.dwSize := SizeOf(ddsd);

    // Lock the surface to directly write to the surface memory
    hr := pDDS.Lock(nil, ddsd, DDLOCK_SURFACEMEMORYPTR or DDLOCK_WAIT, 0);
    if FAILED(hr) then
    begin
      if not RecreateSurfaces then Exit;
      hr := pDDS.Lock(nil, ddsd, DDLOCK_SURFACEMEMORYPTR or DDLOCK_WAIT, 0);
      if FAILED(hr) then Exit;
    end;

    pDst := ddsd.lpSurface;
    // Set 32bit Bitmap Data to DirectDraw7 Draw Buffer
    Move(Pointer(AVideoData.Param1)^, pDst^, AVideoData.Param2);

    pDDS.Unlock(nil);

    DstR := Channel.Rect;

    SrcR := Rect(0, 0, AVideoData.Width, AVideoData.Height);

    FDisplay.Blt(@DstR, FChannelSurface, @SrcR);

    Channel.Timestamp := AVideoData.Timestamp;
   
    DrawChannelText(Channel);

    NeedPaint := True; // Update mainform timer protected property by critical section

  finally
    Canvas.Unlock;
  end;
end;


procedure TMainForm.DrawChannelText(Channel: PChannel);
var
  L, T, W, H: Integer;
  R: TRect;
  HR: HRESULT;
  S, DateStr, TimeStr: string;
  DC: HDC;
  StrSize, DateSize, TimeSize: TSize;
  DstR: TRect;
begin
  L := Channel.Rect.Left;
  T := Channel.Rect.Top;
  W := Channel.Rect.Right - Channel.Rect.Left;
  H := Channel.Rect.Bottom - Channel.Rect.Top;

  Canvas.Lock;
  try
    if (nil = FTextSurface) or
       (FTextSurface.Width <> W) or
       (FTextSurface.Height <> H) then
    begin
      if nil <> FTextSurface then
        FreeAndNil(FTextSurface);

      HR := FDisplay.CreateSurface(FTextSurface, W, H);
      if DD_OK <> HR then Exit;
      FTextSurface.SetColorKey(0);
    end;
    FTextSurface.Clear(0);

    S := IntToStr(Channel.Channel + 1) + ' ' +Channel.ChannelName;
    FTextSurface.DrawText(Font.Handle, S, 3, 2, 0, ColorToRGB(FTextColor));

    HR := FTextSurface.GetDDrawSurface.GetDC(DC);
    if DD_OK <> HR then Exit;
    SelectObject(DC, SelFont.Handle);
    DateStr := DateToStr(DateOf(Channel.TimeStamp));
    GetTextExtentPoint32(DC, PChar(DateStr), Length(DateStr), DateSize);
    TimeStr := TimeToStr(TimeOf(Channel.Timestamp);
    GetTextExtentPoint32(DC, PChar(TimeStr), Length(TimeStr), TimeSize);
    FTextSurface.GetDDrawSurface.ReleaseDC(DC);

    FTextSurface.DrawText(SelFont.Handle, DateStr,
      W - DateSize.cx - 2, 2, 0, ColorToRGB(FTextColor));
    FTextSurface.DrawText(SelFont.Handle, TimeStr,
      W - TimeSize.cx - 2, DateSize.cy + 2, 0, ColorToRGB(FTextColor));
    end;

    HR := FTextSurface.GetDDrawSurface.GetDC(DC);
    if DD_OK <> HR then Exit;
    SelectObject(DC, SelFont.Handle);
    S := Channel.Session.Profile.Address;
    GetTextExtentPoint32(DC, PChar(S), Length(S), StrSize);
    FTextSurface.GetDDrawSurface.ReleaseDC(DC);
    FTextSurface.DrawText(SelFont.Handle, S, 2, H - StrSize.cy - 2, 0, ColorToRGB(FTextColor));

    FDisplay.Blt(L, T, FTextSurface, nil);
  finally
    Canvas.Unlock;
  end;
end;

// fired every 50ms
procedure TMainForm.WMTimer(var msg: TMessage);
begin
  if NeedPaint and (nil <> FDisplay) then
  begin
    FDisplay.Flip;
    NeedPaint := False;
  end;
end;
0
Comment
Question by:byungho
  • 2
5 Comments
 
LVL 28

Expert Comment

by:2266180
ID: 18862679
you have some problems in your code. first of all, remember, that when you have a dedalock, the solution is not inserting another lock. the deadlock means that some locks went wrong.

so, to the problems. in your first procedure, you make some locks and then you exit the procedure in case of error without unlocking. which ... nedless to say it's wrong.

so replace all the exit, with abort calls. this will raise a silent exception and go through all finalize calls.
apply this logic to al your program.

also put the operations between pdds lock and unlock into a try finally. just in case ;)
again, if you have any other lock/unlock calls not protected by try/finally or try/except, then do it now.

that's what I am seeing for now. let me know if this fixes it or not.
0
 

Author Comment

by:byungho
ID: 18863931
I  try to protect exit call with try ... finally ... end; Is it wrong?

I will be put pdds lock and unlock into try ... finally .. end!! thank you!



0
 
LVL 28

Accepted Solution

by:
2266180 earned 500 total points
ID: 18864062
exit, wille xit the procedure and NOT execute the finally statements. that is why you need abort instead of exit.
0
 
LVL 1

Expert Comment

by:Computer101
ID: 21278310
Forced accept.

Computer101
EE Admin
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Unique identifier on a terminal server (rdp) 4 67
DBGrid or StringGrid ? 6 105
Delphi problems to abort a printjob 9 24
Slow Restore if incremental backups using RDiff.exe 4 30
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question