2011-12-07 18 views
0

私はWindows用のアプリケーションを開発しています。私は描画目的でクラスを作成しました。これはいくつかのスレッドによってアクセスされます。このクラスは、mutexロックを使用してスレッドセーフです。子ウィンドウ内でboost :: mutexを使ったC++マルチスレッド

スレッド安全性は問題ではないようですが、WM_SIZEメッセージを処理するときにロックを取得しないようです(他のメッセージを処理するときにロックを取得しますが)理由がわかりません。

クラスには、次のようになります。私は、私の意見では、トラブルを引き起こす可能性がある方法とメンバーを表示するには、それを短縮しました

class DrawChildWindow { 
    typedef boost::mutex::scoped_lock  scoped_lock; 
    typedef boost::mutex::scoped_try_lock scoped_try_lock; 
    typedef std::map<HWND, HDC>   WindowMap; 
public: 
    DrawChildWindow(HWND hWndParent); 
    ~DrawChildWindow(); 

    // Will move the child window and repaint it 
    void move(int x, int y, unsigned int cx, unsigned int cy); 

    // Returns the HDC stored in the WindowMap 
    HDC beginPaint(); 
    // Displays the edited HDC on the client area of the child window 
    void endPaint(); 
private: 
    static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 

    boost::mutex  m_mutexLocal;   // for work with member variables 
    static boost::mutex s_mutexGlobal;  // for work with static variables 

    static WindowMap s_map;    // Manages the created child windows 
    HWND    m_hWnd;    // Handle of the child window 
}; 

。これは、それぞれの実装です:

DrawChildWindow::DrawChildWindow(HWND hWndParent) { 
    // I've cut the once-only registration of the window class here 
    scoped_lock lockG(s_mutexGlobal); 
    scoped_lock lockL(s_mutexLocal); 

    m_hWnd = CreateWindow(L"DrawChildWindow", NULL, 
     WS_CHILDWINDOW | WS_DLGFRAME | WS_VISIBLE, 
     0, 0, 0, 0, 
     m_hWndParent, NULL, __DCW_HINST, NULL); 
    s_map[m_hWnd] = NULL; 
} 

DrawChildWindow::~DrawChildWindow() { 
    scoped_lock lockG(s_mutexGlobal); 
    scoped_lock lockL(s_mutexLocal); 

    WindowMap::iterator it = s_map.find(m_hWnd); 
    if(it != s_map.end()) 
     s_map.erase(it); 
    DestroyWindow(); 
} 

void DrawChildWindow::move(int x, int y, unsigned int cx, unsigned int cy) { 
    scoped_lock lockL(s_mutexLocal); 

    MoveWindow(m_hWnd, x, y, cx, cy, TRUE); 
} 

HDC DrawChildWindow::beginPaint() { 
    scoped_lock lockG(s_mutexGlobal); 
    scoped_lock lockL(s_mutexLocal); 

    WindowMap::iterator it = s_map.find(m_hWnd); 
    if(it != s_map.end()) { 
     if(!it->second) { 
      // I create a compatible DC here 
      // and fit it to match the client area size 
     } 
     // I clear the background of the DC here 
     return it->second; 
    } 
    // This should never happen 
    return NULL; 
} 

void DrawChildWindow::endPaint() { 
    scoped_lock lockG(s_mutexGlobal); 
    scoped_lock_lockL(m_mutexLocal); 

    WindowMap::iterator it = s_map.find(m_hWnd); 
    if(it != s_map.end()) { 
     if(it->second) { 
      // I BitBlt the HDC into the client area here 
     } 
    } 
} 

LRESULT CALLBACK DrawChildWindow::WndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam) { 
    switch(uiMessage) { 
    case WM_SIZE: 
     { // This is the problematic block 
      scoped_try_lock lockG(s_mutexGlobal); 
      // This is never true 
      if(lockG.try_lock()) { 
       WindowMap::iterator it = s_map.find(hWnd); 
       if(it != s_map.end() && it->second) { 
        DeleteDC(it->second); 
        it->second = NULL; 
       } 
      } 
     } 
     return 0; 
    case WM_PAINT: 
     { 
      scoped_lock lockG(s_mutexGlobal); 
      PAINTSTRUCT ps; 
      HDC hDC = BeginPaint(hWnd, &ps); 
      WindowMap::iterator it = s_map.find(hWnd); 
      if(it != s_map.end() && it->second) { 
       // I BitBlt it->second to hDC here 
      } 
      else { 
       // Draw a notification that no data is available 
      } 
      EndPaint(hWnd, &ps); 
     } 
     return 0; 
    } 
    return DefWindowProc(hWnd, uiMessage, wParam, lParam); 
} 

boost::mutex    DrawChildWindow::s_mutexGlobal; 
DrawChildWindow::WindowMap DrawChildWindow::s_map   = WindowMap(); 

私はWM_SIZECreateWindow()ながら呼び出されるという事実を認識しています - それはs_mutexGlobalが実際にロックされている私のコンストラクタに呼び出されます。これが私がscoped_try_lockとして実装した理由です。

親ウィンドウのサイズが変更されたとき、私は子ウィンドウのサイズを調整するためにmove()を呼び出して、それらが正しく調整されますが、s_mapHDCが破壊されることはありません、と私はそこにs_mutexGlobalをロックできない理由を理解することはできません。

答えて

0

問題が

if(s_mutexGlobal.tryLock()) { 
    WindowMap::iterator it = s_map.find(hWnd); 
    if(it != s_map.end() && it->second) { 
     DeleteDC(it->second); 
     it->second = NULL; 
    } 
    s_mutexGlobal.unlock(); 
} 

代わりにscoped_try_lockを使用することによって解決することができます。私は実験中にこれを発見しましたが、誰かがこの行動の説明をしていればなおさら感謝しています。

関連する問題