VC++关于使用WaitForSingleObject等待线程安全退出,出现死机问题的解决

902 阅读2分钟

1、MFC项目场景如下:

主线程新建了子线程:

CWinThread *m_pThread_SysReset;

m_pThread_SysReset= AfxBeginThread(ThreadSysReset this);

主界面等待子线程退出时,主线程主动调用了函数:
WaitForSingleObject(m_pThread_SysReset->m_hThread, INFINITE);
目的是让子待线程安全退出,但是子线程此时正在执行SendMesage发消息函数,主线程就会卡死。而如果子线程改为PostMessage发就不会卡死。为什么呢?

原来在工作线程中使用了SendMesage,它是阻塞方式发消息,这样的话在主线程中使用了waitforSingleObject,主线程就会被阻塞,要是工作线程也使用了消息循环与主线程相关的操作,那么因为主线程已经被阻塞了,所以子线程得不到相应,那么就出现假死了。

实际上,我们可以不使用WaitForSingleObject,因为MFC主线程在不被关闭的话是不会结束的,所以不能使用WaitForSingleObject这样的函数进行等待。但是很多情况下,我们又需要知道我们创建的工作线程的情况,所以还是需要了解工作线程的返回值。那么我们可以使用微软提供的另一个函数MsgWaitForMultipleObjects。

2、怎么解决SendMessage死机问题?使用以下源码即可解决!不再使用WaitForSingleObject,而是使用MsgWaitForMultipleObjects函数。

如此一来,无论子线程怎么发消息,SendMessage也好,PostMessage也罢,都OK!

m_pThread_SysReset = ThreadFun_StartRun(&m_pThread_SysReset, ThreadSystemReset, this);

void CViewImage::ThreadFun_ExitThread(void)
{
	m_bExit = true;
	ThreadFun_WaitForObject(&m_pThread_SysReset);//等待线程退出
}

CWinThread *CViewImage::ThreadFun_StartRun(CWinThread **pThread, AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority)
{
	if (*pThread != NULL)
	{
		delete *pThread;
		*pThread = NULL;
	}

	//启动线程,初始为挂起状态
	*pThread = AfxBeginThread(pfnThreadProc, pParam, nPriority, 0, CREATE_SUSPENDED);

	if (*pThread != NULL)
	{
		//线程结束时不自动撤销
		(*pThread)->m_bAutoDelete = FALSE;
		//恢复线程运行
		(*pThread)->ResumeThread();
	}

	return *pThread;
}

void CViewImage::ThreadFun_WaitForObject(CWinThread **pThread)
{
	if (*pThread == NULL)
	{
		return;
	}

	while (1)
	{
		DWORD result;
		MSG msg;
		result = MsgWaitForMultipleObjects(1, &(*pThread)->m_hThread, FALSE, INFINITE, QS_ALLINPUT);

		if (result == WAIT_OBJECT_0 + 1)
		{
			//响应windows消息
			PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			//线程运行结束(result==WAIT_OBJECT_0) ||
			//传递了一个无效的句柄(result==WAIT_FAILED) ||
			//线程等待时间已到(result==WAIT_TIMEOUT) ||
			//其他情况(...)
			break;
		}
	}

	delete *pThread;
	*pThread = NULL;
}