【问题标题】:C++ Multithreading with boost::mutex within a child window在子窗口中使用 boost::mutex 的 C++ 多线程
【发布时间】:2011-12-07 12:59:31
【问题描述】:

我正在为 Windows 开发一个应用程序。我写了一个用于绘图的类,它将被多个线程访问。通过使用互斥锁,该类是线程安全的。

好消息是,线程安全似乎不是问题,但是,我在处理 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

【问题讨论】:

    标签: c++ winapi boost mutex


    【解决方案1】:

    问题可以通过使用来解决

    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。我在实验时发现了这一点,如果有人对此行为有解释,我仍然会感激不尽。

    【讨论】:

      猜你喜欢
      • 2013-08-27
      • 1970-01-01
      • 2011-07-28
      • 2011-12-13
      • 2012-12-27
      • 2018-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多