创建一个简单的MFC对话框应用程序,其中包含几个按钮来控制线程的创建、挂起、恢复、结束和等待退出。
注意:在VC6.0中,我们需要使用AfxBeginThread来创建工作者线程,并确保线程安全退出。
我们将创建一个工作者线程函数,该函数将执行一个循环,直到收到退出信号。
同时,我们将在对话框类中管理线程句柄和状态。
步骤:
创建一个MFC对话框应用程序。
在对话框上添加按钮:开始、挂起、恢复、结束、退出。
在对话框类中添加线程句柄和事件(或标志)用于控制线程退出。
实现工作者线程函数,该函数循环检查退出事件。
在对话框的按钮事件中控制线程。
我们使用事件(CEvent)来通知线程退出。
由于我们使用AfxBeginThread,我们将传递对话框的this指针给线程函数,以便线程可以访问对话框类中的事件。
但是,注意:在VC6.0中,线程函数必须是静态的或全局的,所以我们通常使用静态成员函数,并通过参数传递this指针。
首先,在对话框头文件中声明:
// 线程函数(静态成员函数)
static UINT WorkerThread(LPVOID pParam);
// 线程句柄
CWinThread* m_pThread;
// 事件,用于通知线程退出
CEvent m_EventExit;
// 线程是否正在运行的标志
BOOL m_bRunning;
我们将创建一个简单的对话框,上面有5个按钮:IDC_BUTTON_START, IDC_BUTTON_SUSPEND, IDC_BUTTON_RESUME, IDC_BUTTON_STOP, IDC_BUTTON_EXIT。
- 资源头文件 resource.h
cpp
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by MyThread.rc
//
#define IDM_ABOUTBOX 0x0010
#define IDD_ABOUTBOX 100
#define IDS_ABOUTBOX 101
#define IDD_MYTHREAD_DIALOG 102
#define IDC_STATUS 103
#define IDC_PROGRESS 104
#define IDC_BTN_START 105
#define IDC_BTN_SUSPEND 106
#define IDC_BTN_RESUME 107
#define IDC_BTN_STOP 108
#define IDC_BTN_EXIT 109
#define IDC_BTN_SAFE_STOP 110
#define IDR_MAINFRAME 128
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
- 预编译头文件 stdafx.h
cpp
// stdafx.h
#include <afxwin.h> // MFC core
#include <afxext.h> // MFC extensions
#include <afxdisp.h> // MFC Automation
#include <afxdtctl.h> // IE4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // Windows Common Controls
#endif
#include <afxmt.h> // 多线程同步类 (CEvent)
- 对话框头文件 MyThreadDlg.h
cpp
// MyThreadDlg.h
#if !defined(AFX_MYTHREADDLG_H__)
#define AFX_MYTHREADDLG_H__
#include "resource.h"
#define WM_UPDATE_PROGRESS (WM_USER + 100)
#define WM_THREAD_FINISHED (WM_USER + 101)
class CMyThreadDlg : public CDialog
{
public:
CMyThreadDlg(CWnd* pParent = NULL);
CWinThread* m_pThread;
BOOL m_bThreadRunning;
BOOL m_bThreadSuspended;
CEvent m_EventStop; // 通知线程退出的事件
static UINT WorkerThread(LPVOID pParam);
CProgressCtrl m_Progress;
CStatic m_StatusText;
CButton m_BtnStart, m_BtnSuspend, m_BtnResume, m_BtnStop, m_BtnExit;
UINT DoWork(); // 工作线程主函数
// 同步 UI 更新(仅 UI 线程调用)
void UpdateProgress(int nPos);
void UpdateStatus(LPCTSTR lpszStatus);
protected:
virtual void DoDataExchange(CDataExchange* pDX);
DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnInitDialog();
afx_msg void OnBtnStart();
afx_msg void OnBtnSuspend();
afx_msg void OnBtnResume();
afx_msg void OnBtnStop();
afx_msg void OnBtnExit();
afx_msg void OnDestroy();
// 自定义消息处理
afx_msg LRESULT OnUpdateProgress(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnThreadFinished(WPARAM wParam, LPARAM lParam);
};
#endif
- 对话框实现文件 MyThreadDlg.cpp
cpp
// MyThreadDlg.cpp
#include "stdafx.h"
#include "resource.h"
#include "MyThreadDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CMyThreadDlg, CDialog)
ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
ON_BN_CLICKED(IDC_BTN_SUSPEND, OnBtnSuspend)
ON_BN_CLICKED(IDC_BTN_RESUME, OnBtnResume)
ON_BN_CLICKED(IDC_BTN_STOP, OnBtnStop)
ON_BN_CLICKED(IDC_BTN_EXIT, OnBtnExit)
ON_WM_DESTROY()
ON_MESSAGE(WM_UPDATE_PROGRESS, OnUpdateProgress)
ON_MESSAGE(WM_THREAD_FINISHED, OnThreadFinished)
END_MESSAGE_MAP()
CMyThreadDlg::CMyThreadDlg(CWnd* pParent /*=NULL*/)
: CDialog(IDD_MYTHREAD_DIALOG, pParent)
{
m_pThread = NULL;
m_bThreadRunning = FALSE;
m_bThreadSuspended = FALSE;
}
BOOL CMyThreadDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 关联控件变量
m_Progress.SubclassDlgItem(IDC_PROGRESS, this);
m_StatusText.SubclassDlgItem(IDC_STATUS, this);
m_BtnStart.SubclassDlgItem(IDC_BTN_START, this);
m_BtnSuspend.SubclassDlgItem(IDC_BTN_SUSPEND, this);
m_BtnResume.SubclassDlgItem(IDC_BTN_RESUME, this);
m_BtnStop.SubclassDlgItem(IDC_BTN_STOP, this);
m_BtnExit.SubclassDlgItem(IDC_BTN_EXIT, this);
m_Progress.SetRange(0, 100);
// 初始按钮状态
m_BtnSuspend.EnableWindow(FALSE);
m_BtnResume.EnableWindow(FALSE);
m_BtnStop.EnableWindow(FALSE);
UpdateStatus(_T("准备就绪"));
return TRUE;
}
void CMyThreadDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
// 静态线程函数
UINT CMyThreadDlg::WorkerThread(LPVOID pParam)
{
CMyThreadDlg* pDlg = (CMyThreadDlg*)pParam;
return pDlg ? pDlg->DoWork() : 0;
}
// 工作线程主函数 - 移除所有同步 UI 调用
UINT CMyThreadDlg::DoWork()
{
m_bThreadRunning = TRUE;
for (int i = 0; i <= 100; i++)
{
// 检查停止事件
if (WaitForSingleObject(m_EventStop.m_hObject, 0) == WAIT_OBJECT_0)
break; // 直接退出,不更新状态
// 异步更新进度
PostMessage(WM_UPDATE_PROGRESS, i, 0);
Sleep(100); // 模拟工作
}
m_bThreadRunning = FALSE;
// 通知 UI 线程工作结束
::PostMessage(m_hWnd, WM_THREAD_FINISHED, 0, 0);
return 0;
}
// 同步更新进度(仅 UI 线程调用)
void CMyThreadDlg::UpdateProgress(int nPos)
{
if (::IsWindow(m_Progress.m_hWnd))
m_Progress.SetPos(nPos);
}
// 同步更新状态(仅 UI 线程调用)
void CMyThreadDlg::UpdateStatus(LPCTSTR lpszStatus)
{
if (::IsWindow(m_StatusText.m_hWnd))
m_StatusText.SetWindowText(lpszStatus);
}
// 处理进度更新消息
LRESULT CMyThreadDlg::OnUpdateProgress(WPARAM wParam, LPARAM lParam)
{
UpdateProgress((int)wParam);
return 0;
}
// 处理线程结束消息
LRESULT CMyThreadDlg::OnThreadFinished(WPARAM wParam, LPARAM lParam)
{
// 清理线程句柄
if (m_pThread != NULL)
{
CloseHandle(m_pThread->m_hThread);
m_pThread = NULL;
}
// 更新按钮状态
m_BtnStart.EnableWindow(TRUE);
m_BtnSuspend.EnableWindow(FALSE);
m_BtnResume.EnableWindow(FALSE);
m_BtnStop.EnableWindow(FALSE);
UpdateStatus(_T("线程已停止"));
return 0;
}
// 开始线程
void CMyThreadDlg::OnBtnStart()
{
if (m_pThread != NULL)
{
MessageBox(_T("线程已在运行"), _T("提示"), MB_OK | MB_ICONINFORMATION);
return;
}
m_EventStop.ResetEvent();
// 以挂起状态创建,然后手动启动
m_pThread = AfxBeginThread(WorkerThread, this,
THREAD_PRIORITY_NORMAL, 0,
CREATE_SUSPENDED, NULL);
if (m_pThread == NULL)
{
MessageBox(_T("创建线程失败"), _T("错误"), MB_OK | MB_ICONERROR);
return;
}
m_pThread->ResumeThread();
// 更新按钮
m_BtnStart.EnableWindow(FALSE);
m_BtnSuspend.EnableWindow(TRUE);
m_BtnStop.EnableWindow(TRUE);
m_BtnResume.EnableWindow(FALSE);
UpdateStatus(_T("线程已启动"));
}
// 挂起线程
void CMyThreadDlg::OnBtnSuspend()
{
if (m_pThread == NULL || !m_bThreadRunning) return;
DWORD nCount = m_pThread->SuspendThread();
m_bThreadSuspended = TRUE;
CString str;
str.Format(_T("线程已挂起 (挂起计数 %d)"), nCount);
UpdateStatus(str);
m_BtnSuspend.EnableWindow(FALSE);
m_BtnResume.EnableWindow(TRUE);
}
// 恢复线程
void CMyThreadDlg::OnBtnResume()
{
if (m_pThread == NULL || !m_bThreadRunning) return;
DWORD nCount = m_pThread->ResumeThread();
m_bThreadSuspended = FALSE;
CString str;
str.Format(_T("线程已恢复 (剩余挂起计数 %d)"), nCount - 1);
UpdateStatus(str);
m_BtnResume.EnableWindow(FALSE);
m_BtnSuspend.EnableWindow(TRUE);
}
// 停止线程 - 仅发送信号,不等待
void CMyThreadDlg::OnBtnStop()
{
if (m_pThread == NULL) return;
// 通知线程退出
m_EventStop.SetEvent();
// 如果被挂起,先恢复
if (m_bThreadSuspended)
{
m_pThread->ResumeThread();
m_bThreadSuspended = FALSE;
}
// 更新 UI 状态(开始按钮保持禁用,由线程结束消息启用)
UpdateStatus(_T("正在停止线程..."));
m_BtnStop.EnableWindow(FALSE);
m_BtnSuspend.EnableWindow(FALSE);
m_BtnResume.EnableWindow(FALSE);
}
// 退出程序
void CMyThreadDlg::OnBtnExit()
{
if (m_pThread != NULL)
OnBtnStop(); // 请求停止
// 给线程一点时间退出(可选,OnDestroy 中会等待)
Sleep(200);
EndDialog(IDOK);
}
// 对话框销毁时确保线程结束
void CMyThreadDlg::OnDestroy()
{
if (m_pThread != NULL)
{
m_EventStop.SetEvent();
if (m_bThreadSuspended)
m_pThread->ResumeThread();
// 等待线程结束(最多 2 秒)
WaitForSingleObject(m_pThread->m_hThread, 2000);
// 若仍未结束,强制终止(极少数情况)
if (WaitForSingleObject(m_pThread->m_hThread, 0) != WAIT_OBJECT_0)
TerminateThread(m_pThread->m_hThread, 0);
CloseHandle(m_pThread->m_hThread);
m_pThread = NULL;
}
CDialog::OnDestroy();
}
运行程序
