2011-12-07 24 views
0

我正在开发一个Windows应用程序。我写了一个用于绘图的类,它将被多个线程访问。该类通过使用互斥锁实现线程安全。C++多线程与子窗口内的boost :: mutex

好的是,线程安全似乎不是一个问题,但是,我似乎永远不会在处理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_SIZE将被调用,而CreateWindow() - 所以它会在我的构造,其中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来解决。我在试验时发现了这一点,如果有人对此行为有解释,我们仍然会很感激。

相关问题