CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    Sep 2013
    Posts
    5

    Question Deadlock on device context

    Hi all,
    Let me share few codeblocks with you, hoping that someone would se something strange.

    Here's method used to draw both opaque and transparent images, I've left only part of code related to transparent bitmap drawing.
    Code:
        
    void PicturePool::draw(HDC destDC,...)
    {
        ...
    
        // create bitmap, create dc for bitmap, put bitmap in dc
        HBITMAP hBitmap = CreateDIBitmap(destDC, (LPBITMAPINFOHEADER) (p.bmInfo), 
                                         CBM_INIT, lpDIBBits, p.bmInfo, DIB_RGB_COLORS);
        HDC bmpDC = CreateCompatibleDC(destDC);
        HBITMAP hOldBmp = (HBITMAP)SelectObject(bmpDC, hBitmap);
    
        // create mask, create dc for mask, put mask in dc
        HBITMAP hMask = createTransparentMask(picName, destDC,
                                              width, height,
                                              RGB2LONG(transparentColor),
                                              hBitmap);
        HDC maskDC = CreateCompatibleDC(destDC);
        HBITMAP hOldMask = (HBITMAP)SelectObject(maskDC, hMask);
    
        ...
    
        // 1) make transparent parts in bmpDC
        InvertRect(maskDC, &rect);
        BitBlt(bmpDC, 0, 0, width, height, maskDC, 0, 0, SRCAND);
    
        // 2) put non transparent parts in destDC
        InvertRect(maskDC, &rect);
        BitBlt(destDC, xpos, yDest, width, height, maskDC, 0, 0, SRCAND);
    
        // 3) put transparent parts in destDC
        BitBlt(destDC, xpos, yDest, width, height, bmpDC, 0, 0, SRCPAINT);
    
        // cleanup
        if (hBitmap != NULL) { DeleteObject(SelectObject(bmpDC, hOldBmp)); }
        DeleteDC(bmpDC);
    
        SelectObject(maskDC, hOldMask);  // hMask is not deleted on purpose, it is stored in cache for later use
        DeleteDC(maskDC);    
    }

    From the code above you see that bitmap mask is created using createTransparentMask method. Here's a code block just in case:

    Code:
    HBITMAP PicturePool::createTransparentMask(...)
    {
        ... 
    
        HDC hdcMem, hdcMem2;
        HBITMAP maskBitmap = NULL;
    
        // Create monochrome (1 bit) mask bitmap.
        maskBitmap = CreateBitmap(width, height, 1, 1, NULL);
       
        // Get some HDCs that are compatible with the display driver  
        hdcMem = CreateCompatibleDC(dc);
        hdcMem2 = CreateCompatibleDC(dc);
       
        HBITMAP oldBitmap = (HBITMAP)SelectObject(hdcMem, bitmap);
        HBITMAP oldMask = (HBITMAP)SelectObject(hdcMem2, maskBitmap);
        
        // Set the background color of the color image to the color you want to be transparent.
        SetBkColor(hdcMem, transparentColor);
    
        // Copy the bits from the color image to the B+W mask... everything with
        // the background color ends up white while everything else ends up black
        BitBlt(hdcMem2, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
    
        // Take our new mask and use it to turn the transparent color in our
        // original color image to black so the transparency effect will work right.
        BitBlt(hdcMem, 0, 0, width, height, hdcMem2, 0, 0, SRCINVERT);
    
        // Clean up.  
        SelectObject(hdcMem, oldBitmap);
        SelectObject(hdcMem2, oldMask);
        DeleteDC(hdcMem);
        DeleteDC(hdcMem2);
        
        ...
    }
    Now let me explain (or at least try) what seems to be the problem. Code works fine for a certain period of time, then "deadlock" appears on destDC, resulting stuck on following winapi function using that dc and it is always happening after drawing 'somewhat' large bitmap (1024x685, ~2MB).
    Simple explanation: draw method executes successfully numerous times, large bitmap (problematic one) is also successfuly displayed numerous times, and than it got stuck on first SelectObject(destDC, anyObject) after draw method. Whole application is displayed 1024x768 pixels, winxp. If I forgot something, I'll add later.

    Any suggestion or hint would be really appreciated.

  2. #2
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: Deadlock on device context

    Where do you call DeleteObject for the maskBitmap ?
    Victor Nijegorodov

  3. #3
    Join Date
    Sep 2013
    Posts
    5

    Re: Deadlock on device context

    Mask bitmap is created only once per image (on firs use) and reused later on. It is kept in a map. That part of code is missing here.

  4. #4
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: Deadlock on device context

    It is bad that a lot of "parts of code are missing here"
    Well, did you try to see in the project explorer what happens with your application: handle leaks, some other problems?
    Victor Nijegorodov

  5. #5
    Join Date
    Sep 2013
    Posts
    5

    Re: Deadlock on device context

    Quote Originally Posted by VictorN View Post
    It is bad that a lot of "parts of code are missing here"
    Sorry my bad, I haven't copy/pasted all code blocks from methods. So there is a map to store pictures and masks (in order to load each picture only once). I have tried without picture caching and behaviour is the same.

    Quote Originally Posted by VictorN View Post
    Well, did you try to see in the project explorer what happens with your application: handle leaks, some other problems?
    Process explorer is somewhat unusable in situation when deadlock appears. The only thing that I can do after deadlock is to reboot, yes the whole system reboot, believe it or not.

    There are two things that I can do in order to keep system running without deadlock:

    1) Skip creation of maskBitmap for that specific bitmap like so:
    Code:
    HBITMAP PicturePool::createTransparentMask(...)
    {
        ... 
    
        HDC hdcMem, hdcMem2;
        HBITMAP maskBitmap = NULL;
    
        // Create monochrome (1 bit) mask bitmap.
        if (!problematicBitmap)
          maskBitmap = CreateBitmap(width, height, 1, 1, NULL);
       
        // Get some HDCs that are compatible with the display driver  
        hdcMem = CreateCompatibleDC(dc);
        hdcMem2 = CreateCompatibleDC(dc);
       
        HBITMAP oldBitmap = (HBITMAP)SelectObject(hdcMem, bitmap);
        HBITMAP oldMask = (HBITMAP)SelectObject(hdcMem2, maskBitmap);
        
        // Set the background color of the color image to the color you want to be transparent.
        SetBkColor(hdcMem, transparentColor);
    
        // Copy the bits from the color image to the B+W mask... everything with
        // the background color ends up white while everything else ends up black
        BitBlt(hdcMem2, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
    
        // Take our new mask and use it to turn the transparent color in our
        // original color image to black so the transparency effect will work right.
        BitBlt(hdcMem, 0, 0, width, height, hdcMem2, 0, 0, SRCINVERT);
    
        // Clean up.  
        SelectObject(hdcMem, oldBitmap);
        SelectObject(hdcMem2, oldMask);
        DeleteDC(hdcMem);
        DeleteDC(hdcMem2);
        
        ...
    }
    Regarding code above, I have tried some alternatives for CreateBitmap(width, height, 1, 1, NULL) without any success (tried with CreateBitmapIndirect and probably some other functions, I forgot...)


    2) Don't skip maskBitmap creation but skip two BitBlt functions related to maskDC (dc that keeps maskBitmap)
    Code:
    void PicturePool::draw(HDC destDC,...)
    {
        ...
    
        // create bitmap, create dc for bitmap, put bitmap in dc
        HBITMAP hBitmap = CreateDIBitmap(destDC, (LPBITMAPINFOHEADER) (p.bmInfo), 
                                         CBM_INIT, lpDIBBits, p.bmInfo, DIB_RGB_COLORS);
        HDC bmpDC = CreateCompatibleDC(destDC);
        HBITMAP hOldBmp = (HBITMAP)SelectObject(bmpDC, hBitmap);
    
        // create mask, create dc for mask, put mask in dc
        HBITMAP hMask = createTransparentMask(picName, destDC,
                                              width, height,
                                              RGB2LONG(transparentColor),
                                              hBitmap);
        HDC maskDC = CreateCompatibleDC(destDC);
        HBITMAP hOldMask = (HBITMAP)SelectObject(maskDC, hMask);
    
        ...
    
        // 1) make transparent parts in bmpDC
        InvertRect(maskDC, &rect);
        if (!problematicBitmap)
          BitBlt(bmpDC, 0, 0, width, height, maskDC, 0, 0, SRCAND);
    
        // 2) put non transparent parts in destDC
        InvertRect(maskDC, &rect);
        if (!problematicBitmap)
          BitBlt(destDC, xpos, yDest, width, height, maskDC, 0, 0, SRCAND);
    
        // 3) put transparent parts in destDC
        BitBlt(destDC, xpos, yDest, width, height, bmpDC, 0, 0, SRCPAINT);
    
        // cleanup
        if (hBitmap != NULL) { DeleteObject(SelectObject(bmpDC, hOldBmp)); }
        DeleteDC(bmpDC);
    
        SelectObject(maskDC, hOldMask);  // hMask is not deleted on purpose, it is stored in cache for later use
        DeleteDC(maskDC);    
    }
    Regarding code above, I have not tried any altenatives for BitBlt since I can't use any (OpenGL or D3D are not an option), my hands are tied.

    Both of this things are not the solution offcourse since the image is not displayed in desired way. I would like to focus on 2nd 'workaround' (skiping BitBlt) but I don't know what to do. Are there any known issues with memory dc and BitBlt, maybe something related to image size and BitBlt, anything?

    Sorry for this longer post and Viktor thanks for discussion.

  6. #6
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Deadlock on device context

    Code works fine for a certain period of time, then "deadlock" appears on destDC,
    large bitmap (problematic one) is also successfuly displayed numerous times
    How many times? Is it always the same number or different before 'deadlock' occurs? Is the problem repeatable (ie do x, y, z and after t times it deadlocks)? Does the same problem occur on just the one computer or on others? Does your program use multi-threading?
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  7. #7
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Deadlock on device context

    Quote Originally Posted by akansuki View Post
    Sorry my bad, I haven't copy/pasted all code blocks from methods. So there is a map to store pictures and masks (in order to load each picture only once). I have tried without picture caching and behaviour is the same.
    Why do you not check return values for all of your functions? This should be done especially for these cases where the device contexts (where depending on where they were derived from, can be buggy, such as video devices) can play a major role in how these functions behave.

    Regards,

    Paul McKenzie

  8. #8
    Join Date
    Sep 2013
    Posts
    5

    Re: Deadlock on device context

    Quote Originally Posted by 2kaud View Post
    How many times? Is it always the same number or different before 'deadlock' occurs? Is the problem repeatable (ie do x, y, z and after t times it deadlocks)? Does the same problem occur on just the one computer or on others? Does your program use multi-threading?
    So far I couldn't recognize any pattern, it usually runs for ~half an hour. I can check how many times that picture is displayed before deadlock but I can tell you in advance that it's not always the same number of times (I'll doublecheck that). Application is intended to run (or should I say its running) on multiple computers but they all have the exact same hardware, so results from other computers are actually all the same. And yes, program uses multi-threading.

    Quote Originally Posted by Paul McKenzie View Post
    Why do you not check return values for all of your functions? This should be done especially for these cases where the device contexts (where depending on where they were derived from, can be buggy, such as video devices) can play a major role in how these functions behave.

    Regards,

    Paul McKenzie
    I've done that already, return values are always the same, all BitBlt functions return 1 (nonzero lets say), DeleteObject also, DeleteDC also. I can also double check this and share logs if you like.

  9. #9
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Deadlock on device context

    While the program is running, have you checked its memory usage to see if the program has a memory leak? Does the memory usage stay the same or does it keep increasing?
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  10. #10
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Deadlock on device context

    Quote Originally Posted by akansuki View Post
    So far I couldn't recognize any pattern, it usually runs for ~half an hour. I can check how many times that picture is displayed before deadlock but I can tell you in advance that it's not always the same number of times (I'll doublecheck that).
    What could be a programmers fault:
    Memory leak, buffer overrun, multithreading issue (race condition, re-entrancy, etc.)

    What would be fault of the hardware where you are obtaining the device context:
    Buggy driver(s) (assuming that every return value returns OK).
    I've done that already, return values are always the same, all BitBlt functions return 1 (nonzero lets say), DeleteObject also, DeleteDC also. I can also double check this and share logs if you like.
    The point is that the code to check return values should be permanently in the code base, and not there temporarily just to check for bugs.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; September 27th, 2013 at 06:06 PM.

  11. #11
    Join Date
    Sep 2013
    Posts
    5

    Re: Deadlock on device context

    Quote Originally Posted by 2kaud View Post
    While the program is running, have you checked its memory usage to see if the program has a memory leak? Does the memory usage stay the same or does it keep increasing?
    I can try to track memory usage while the program is running but as soon as deadlock appears I am unable to see anything since program is running in fullscreen mode. Besides, memory leak is not the suspect here, I'm 99% sure that it's deadlock. Same software worked for a long time without problems and now that I think of it, problems came with new hardware.


    Quote Originally Posted by Paul McKenzie View Post
    What could be a programmers fault:
    Memory leak, buffer overrun, multithreading issue (race condition, re-entrancy, etc.)

    What would be fault of the hardware where you are obtaining the device context:
    Buggy driver(s) (assuming that every return value returns OK).
    The point is that the code to check return values should be permanently in the code base, and not there temporarily just to check for bugs.

    Regards,

    Paul McKenzie
    You are right, return values should be permanently in the code.
    Following your suggestion, I'll try with different drivers and see the results.


    Quote Originally Posted by 2kaud View Post
    There are two things that I can do in order to keep system running without deadlock:

    1) Skip creation of maskBitmap for that specific bitmap like so...

    2) Don't skip maskBitmap creation but skip two BitBlt functions related to maskDC (dc that keeps maskBitmap)...
    Forgot to mention 3rd 'workaround' that will also keep program running, replace problematic image with smaller one (lets say instead of 1024x685 place 400x300).

    As a temporary solution we have introduced 'step by step BitBlt' so instead of one function call of
    BitBlt(destDC, xpos, yDest, width, height, maskDC, 0, 0, SRCAND);
    we have nine successive calls like splitting image to smaller 3x3 images.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured