今天同事问我这个事情,我原本也不大相信的后来测试发现果真存在这个问题,PC上不存在的,测试代码如下:
DWORD WINAPI TestThreadProc(void * pParam)
// 查找Window句柄线程
{
printf("\nStart:%s\n", __FUNCTION__);
FindWindow(NULL, L"asdasdqwejqwe");
printf("\nEnd:%s\n", __FUNCTION__);
return 0;
}
void CErrorReportDialogDlg::OnBnClickedButton1() // MFC 按钮事件响应函数
{
// TODO: 在此添加控件通知处理程序代码
CloseHandle(CreateThread(NULL, 0, TestThreadProc, NULL, 0, 0));
for (int i = 0; i < 10; i++)
{
Sleep(1000);
printf("Sleep %d\n", i);
}
}
//执行完成后的打印
Start:TestThreadProc
Sleep 0
Sleep 1
Sleep 2
Sleep 3
Sleep 4
Sleep 5
Sleep 6
Sleep 7
Sleep 8
Sleep 9
End:TestThreadProc
结果证明在非消息线程(窗口线程)调用FindWindow函数时,MFC内部可能是直接调用SendMessage方式到窗口主线程完成Find操作的,那么刚才的事件响应代码还未返回SendMessage自然就会等待函数返回后才执行,所以出现上述打印结果。
那么我们在开发程序时如果用到锁了,那么这个问题严重时就会出现死锁的情况,死锁测试代码如下:
DWORD WINAPI TestThreadProc(void * pParam)
// 查找Window句柄线程
{
EnterCriticalSection(&lock); // 同步处理某些事情
DoSometings();
FindWindow(NULL, L"asdasdqwejqwe");
LeaveCriticalSection(&lock);
return 0;
}
void CErrorReportDialogDlg::OnBnClickedButton1() // MFC 按钮事件响应函数
{
// TODO: 在此添加控件通知处理程序代码
CloseHandle(CreateThread(NULL, 0, TestThreadProc, NULL, 0, 0));
EnterCriticalSection(&lock); // 同步处理某些事情
DoSometings();
LeaveCriticalSection(&lock);
}
这种情况一般来说是应该避免的,也就是一般只锁数据操作,但是往往开发中某些函数被多次封装后,就没那么明显了,这个问题也是隐藏的比较深的。