mfc 线程启动、挂起、恢复、停止实例

创建一个简单的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。

  1. 资源头文件 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
  1. 预编译头文件 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)
  1. 对话框头文件 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
  1. 对话框实现文件 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();
}

运行程序

相关推荐
xiaoye-duck2 小时前
《算法题讲解指南:优选算法-滑动窗口》--09长度最小的子数串,10无重复字符的最长字串
c++·算法
白太岁2 小时前
Muduo:(5) 主 Reactor 之 Acceptor 与 SubReactor 的分发
服务器·网络·c++·网络协议·tcp/ip
Non importa2 小时前
二分法:算法新手第三道坎
c语言·c++·笔记·qt·学习·算法·leetcode
王老师青少年编程2 小时前
2020年信奥赛C++提高组csp-s初赛真题及答案解析(完善程序第1题)
c++·题解·真题·初赛·信奥赛·csp-s·提高组
学编程的闹钟2 小时前
安装GmSSL3库后用VS编译CMake源码
c语言·c++·ide·开发工具·cmake·visual studio
想放学的刺客10 小时前
整理了120道单片机嵌入式面试题与答案,覆盖了硬件电路和C语言等核心领域。
c语言·c++·stm32·单片机·嵌入式硬件·mcu·51单片机
普通网友12 小时前
多协议网络库设计
开发语言·c++·算法
努力努力再努力wz12 小时前
【Linux网络系列】:TCP 的秩序与策略:揭秘传输层如何从不可靠的网络中构建绝对可靠的通信信道
java·linux·开发语言·数据结构·c++·python·算法
汉克老师12 小时前
GESP2024年3月认证C++二级( 第二部分判断题(1-10))
c++·循环结构·分支结构·gesp二级·gesp2级