Solved

Multithread update screen using directdraw -> DeadLock

Posted on 2007-04-05
5
966 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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Filemaker 14 vs Delphi Embarcadero 7 186
IExtractImage Delphi 14 201
Sending Gmail through Delphi 3 91
Delphi: how to implement a User Shortcut mapper? 1 94
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Video by: Mark
This lesson goes over how to construct ordered and unordered lists and how to create hyperlinks.
Many functions in Excel can make decisions. The most simple of these is the IF function: it returns a value depending on whether a condition you describe is true or false. Once you get the hang of using the IF function, you will find it easier to us…

912 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now