MFC环境下Start&Pause&Stop操作(续):尽快结束任务
来源:互联网 发布:广州软件测试培训 编辑:程序博客网 时间:2024/06/05 17:36
在《MFC环境下Start&Pause&Stop操作》一文中,执行背景任务的线程中有下面一段话:
::WaitForSingleObject(hSleepEvent, 2000);
即线程周期性执行任务中间,会有一个固定的时间间隔。这种情况也是常见的,比如工程中周期性对数据采样的时候。时间有长有短,短的时候,用上面的这种WaitFor是可行的;长的时候,尽管功能不会有什么问题,但用户体验会下降。
为了说明问题,把上面的2s改成20s:
::WaitForSingleObject(hSleepEvent, 20000);
然后试着在Start之后单击Stop,Stop之后立即拖动这个UI的标题栏、或者鼠标单击下面的编辑框,则会较大概率出现下面的无响应:(直接关闭窗口看不出该效果)
为方便说明问题原因,代码再贴一遍:
DWORD WINAPI CStartPauseStopDlg::ThreadProc(LPVOID lpThreadParameter){ CStartPauseStopDlg* pObj = (CStartPauseStopDlg*)lpThreadParameter; HANDLE hSleepEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); for (;;) { if (pObj->m_bStopped) { //::AfxMessageBox("User stopped the task."); break; } pObj->Doit(); ::WaitForSingleObject(hSleepEvent, 20000); } return 0;}void CStartPauseStopDlg::OnBnClickedStop(){ m_bStopped = TRUE; GetDlgItem(IDC_START)->EnableWindow(TRUE); GetDlgItem(IDC_START)->SetWindowText(_T("Start")); GetDlgItem(IDC_PAUSE)->EnableWindow(FALSE); GetDlgItem(IDC_STOP)->EnableWindow(FALSE); ::ResumeThread(m_hThread); CloseThread(); m_dwCurrent = 0;}void CStartPauseStopDlg::CloseThread(){ if (NULL == m_hThread) return; m_bStopped = TRUE; WaitForSingleObject(m_hThread, INFINITE); CloseHandle(m_hThread); m_hThread = NULL;}
单击了Stop按钮之后,会执行OnBnClickedStop()函数,这个函数会唤醒执行线程,然后通过布尔变量m_bStopped让线程自己结束自己。而CloseThread()的WaitFor负责等待。线程真正结束之后,OnBnClickedStop()函数才返回。在这个过程中,拖动UI的标题栏,就会出现无响应。
如果唤醒线程后,线程刚好从for循环的下一句执行,立即判断出现要退出循环,则不会无响应。如果刚好碰到线程恢复后要执行周期性等待的WaitFor(类似于Sleep),则就无响应了。
如前面所述,如果这个等待时间过长,那么用户体验下降。
下面是一种解决方法,利用WaitForMultipleObject,即在原来Event的基础上,再增加一个Stop对应的Event。当用户选择Stop的时候,给该Event设置信号,WaitForMultipleObject可以立即退出。
示例代码:
在头文件中新增一个事件句柄:
HANDLE m_hStopEvent;
实现文件的部分代码(关注m_hStopEvent的部分):
BOOL CStartPauseStopDlg::OnInitDialog(){ ... // TODO: Add extra initialization here m_hStopEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); m_hThread = NULL; m_bStopped = FALSE; m_dwCurrent = 0; GetDlgItem(IDC_PAUSE)->EnableWindow(FALSE); GetDlgItem(IDC_STOP)->EnableWindow(FALSE); return TRUE; // return TRUE unless you set the focus to a control}void CStartPauseStopDlg::OnBnClickedStart(){ m_bStopped = FALSE; ::ResetEvent(m_hStopEvent); if (NULL == m_hThread) { m_hThread = ::CreateThread(NULL, 0, ThreadProc, this, 0, NULL); } else { ::ResumeThread(m_hThread); } GetDlgItem(IDC_START)->EnableWindow(FALSE); GetDlgItem(IDC_PAUSE)->EnableWindow(TRUE); GetDlgItem(IDC_STOP)->EnableWindow(TRUE);}void CStartPauseStopDlg::OnBnClickedStop(){ m_bStopped = TRUE; GetDlgItem(IDC_START)->EnableWindow(TRUE); GetDlgItem(IDC_START)->SetWindowText(_T("Start")); GetDlgItem(IDC_PAUSE)->EnableWindow(FALSE); GetDlgItem(IDC_STOP)->EnableWindow(FALSE); ::SetEvent(m_hStopEvent); ::ResumeThread(m_hThread); CloseThread(); m_dwCurrent = 0;}void CStartPauseStopDlg::OnDestroy(){ CDialogEx::OnDestroy(); CloseThread(); ::CloseHandle(m_hStopEvent);}DWORD WINAPI CStartPauseStopDlg::ThreadProc(LPVOID lpThreadParameter){ CStartPauseStopDlg* pObj = (CStartPauseStopDlg*)lpThreadParameter; HANDLE hSleepEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); HANDLE hEvents[2] = {hSleepEvent, pObj->m_hStopEvent}; for (;;) { if (pObj->m_bStopped) { //::AfxMessageBox("User stopped the task."); break; } pObj->Doit(); ::WaitForMultipleObjects(2, hEvents, FALSE, 20000); } return 0;}void CStartPauseStopDlg::CloseThread(){ if (NULL == m_hThread) return; m_bStopped = TRUE; ::SetEvent(m_hStopEvent); WaitForSingleObject(m_hThread, INFINITE); CloseHandle(m_hThread); m_hThread = NULL;}
后记:
以上代码没有CloseHandle(m_hStopEvent);找个地方安放它吧。
- MFC环境下Start&Pause&Stop操作(续):尽快结束任务
- MFC环境下Start&Pause&Stop操作
- MFC环境下Start&Pause&Stop操作(续):我执行完了
- CentOS下安装使用start-stop-daemon
- matrixWorkFlow的结束任务操作
- J2ME通讯相关(要尽快结束的项目)
- windows环境下定时任务的创建 MFC VC
- mysql start mysql stop
- START-STOP-DAEMON
- linux weblogic start stop
- start-stop-daemon example
- start-stop-daemon
- start-stop-daemon命令
- osx openfire stop/start
- man start-stop-daemon
- start-stop-daemon
- start stop 游戏 bat
- start-stop-daemon
- sun.misc.BASE64Decoder报错
- 在GCC和Visual Studio中使用hash_map
- freemarker从头开始(Maven构建)
- React Native 环境搭建攻略
- 01背包问题空间优化
- MFC环境下Start&Pause&Stop操作(续):尽快结束任务
- 服务器性能诊断
- nyoj746整数划分(四)【区间dp】
- Unity3d,获取GPS定位信息
- 防火墙工作模式简介
- Nginx 配置文件总结
- HTML5,CSS,JS知识记录
- System.gc和System.runFinalization区别
- [BZOJ3531] [SDOI2014] 旅行