我刚开始学习MFC,我正在编写一个基于对话框的应用程序,以便更好地理解多线程。
主对话框有一个进度条,一个开始按钮和一个取消按钮。
点击开始按钮,我正在创建一个工作线程进行一些处理(通过API调用),主线程负责进度条。
我已经定义了几个Windows消息来更新并停止进度条状态
WM_UPDATE_CONTROL
WM_STOP_CONTROL
以下是我到目前为止创建的代码
HWND* phObjectHandle;
CWinThread* thread;
void CprogCtrlDlg::OnBnClickedStart() {
phObjectHandle = new HWND; // Set object handle for Worker thread
*phObjectHandle = GetSafeHwnd();
// create worker thread
if(NULL == (thread = AfxBeginThread(ThreadFunc, phObjectHandle))) {
EndDialog(IDCANCEL);
}
AfxMessageBox(L"Thread started");
// Set Progress bar to marquee
}
void CprogCtrlDlg::OnBnClickedCancel() {
// kill the Worker thread
}
UINT CprogCtrlDlg::ThreadFunc(LPVOID pParam) {
HWND *pObjectHandle = static_cast<HWND *>(pParam);
CprogCtrlImpDlg* threadDlg = (CprogCtrlImpDlg*) pParam;
return threadDlg->ThreadFuncRun(pObjectHandle);
}
UINT CprogCtrlDlg::ThreadFuncRun(HWND* pObjectHandle) {
::PostMessage(*pObjectHandle, WM_UPDATE_CONTROL, 0, 0);
// repetitive API CALL in a loop
::PostMessage(*pObjectHandle, WM_STOP_CONTROL, 0, 0);
AfxMessageBox(L"Thread completed");
return 0;
}
如果单击“取消”按钮,我想从Parent线程终止Worker线程。
我尝试使用TerminateThread()(尽管它不是建议的)但我无法杀死该线程。
请评论并分享您对从父线程终止工作线程的想法。
我在Windows 7上使用visual studio 2010
TIA
答案 0 :(得分:5)
我会修改你的代码。
在对话框类中有一些成员变量来保存线程句柄和事件句柄(在构造函数中初始化为NULL):
CWinThread* m_hThread;
HANDLE m_hKillEvent;
使用静态函数作为线程入口点,将对话框this
作为参数传递,然后将调用委托给类实例,以便访问所有对话框的变量:
UINT ThreadFunc(LPVOID pParam)
{
// static thread func - delegate to instance
CprogCtrlDlg* pDlg = static_cast<CprogCtrlDlg*>(pParam);
return pDlg->ThreadFuncRun();
}
启动线程时,也要创建一个事件:
void CprogCtrlDlg::OnBnClickedStart()
{
// create worker thread
m_hKillEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hThread = AfxBeginThread(ThreadFunc, this);
AfxMessageBox(L"Thread started");
}
要杀死线程,只需设置事件并等待线程句柄,这将在死亡时发出信号:
void CprogCtrlDlg::OnBnClickedCancel()
{
// kill the Worker thread
SetEvent(m_hKillEvent);
// wait for it to die
DWORD dwRet = WaitForSingleObject(m_hThread->m_hThread, 5000);
if (dwRet == WAIT_TIMEOUT)
{
// thread failed to die after 5 seconds
// error handling (maybe TerminateThread here)
}
}
在线程函数(现在在对话框类中)中,您可以向自己发布消息以指示进度并使用等待事件来捕获终止请求:
UINT CprogCtrlDlg::ThreadFuncRun()
{
// instance thread func
PostMessage(WM_UPDATE_CONTROL, 0, 0);
// main loop
while (true)
{
// check kill
DWORD dwRet = WaitForSingleObject(m_hKillEvent, 0);
if (dwRet == WAIT_OBJECT_0) break;
// do a little work here and update progress
// ... so this is part of your working loop ...
PostMessage(WM_UPDATE_CONTROL, 0, 1 /*2,3,4,...*/);
}
// normal thread exit
PostMessage(WM_STOP_CONTROL, 0, 0);
return 0;
}
我遗漏了初始化,指针清理,手柄等等,但你得到了我希望的一般想法。
您可以通过多种方式对线程循环进行编码,您可以像上面那样定期检查事件是否已发出信号,或者您可以等待事件发出信号以完成工作。两者都是常见的模式,通常与两个事件一起使用 - 一个用于触发工作,另一个用于查杀。如果等待多个事件,请参阅this answer以了解要注意的一些要点。
对于简单的进度条更新,您可以将事件检查放在工作循环中,如下所示:
UINT CprogCtrlDlg::ThreadFuncRun()
{
// instance thread func
PostMessage(WM_UPDATE_CONTROL, 0, 0);
// main loop
for (int i = 0; i < 100; ++i)
{
// check kill
DWORD dwRet = WaitForSingleObject(m_hKillEvent, 0);
if (dwRet == WAIT_OBJECT_0) break;
// do a little work here and update progress
PostMessage(WM_UPDATE_CONTROL, 0, (LPARAM)i);
}
// normal thread exit
PostMessage(WM_STOP_CONTROL, 0, 0);
return 0;
}