?
Solved

Multithread update screen using directdraw -> DeadLock

Posted on 2007-04-05
5
Medium Priority
?
1,004 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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 2000 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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
Suggested Courses

765 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