【发布时间】: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_map的HDC永远不会被破坏,我不明白为什么我不能在那里锁定s_mutexGlobal。
【问题讨论】: