news 2026/4/23 14:58:47

MFC线程添加安全结束代码实例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MFC线程添加安全结束代码实例

添加线程安全结束代码的原因:1.如果对话框关闭时线程仍在运行,访问已释放内存程序崩溃!2. 资源泄漏风险如线程句柄未关闭、内存未释放、 GDI对象未释放、文件句柄未关闭,程序看似关闭,但进程仍在后台运行,再次启动程序可能失败。这里增加一个SafeTerminateThread()函数用于线程安全结束,在对话框析构函数、OnDestroy消息处理、及停止按钮中调用于线程安全函数。改进后完整代码如下。
SimpleThreadDemoDlg.h

// SimpleThreadDemoDlg.h : header file//#if!defined(AFX_SIMPLETHREADDEMODLG_H__1FDB3406_48D0_44E7_9CE2_1977BCCA5492__INCLUDED_)#defineAFX_SIMPLETHREADDEMODLG_H__1FDB3406_48D0_44E7_9CE2_1977BCCA5492__INCLUDED_#if_MSC_VER>1000#pragmaonce#endif// _MSC_VER > 1000/////////////////////////////////////////////////////////////////////////////// CSimpleThreadDemoDlg dialogclassCSimpleThreadDemoDlg:publicCDialog{// Constructionpublic:CSimpleThreadDemoDlg(CWnd*pParent=NULL);// standard constructorvirtual~CSimpleThreadDemoDlg();// 析构函数// 线程句柄HANDLE m_hThread;// 事件对象,用于线程同步HANDLE m_hStopEvent;// 线程控制标志// 线程控制BOOL m_bStopThread;// TRUE表示线程应该停止BOOL m_bThreadActive;// TRUE表示线程正在运行// 线程参数结构structTHREAD_PARAM{CSimpleThreadDemoDlg*pDlg;intnCounter;};private:// 添加安全终止方法voidSafeTerminateThread();// 静态线程函数staticUINTThreadProc(LPVOID pParam);// 线程工作函数voidDoThreadWork(intnIteration);// Dialog Data//{{AFX_DATA(CSimpleThreadDemoDlg)enum{IDD=IDD_SIMPLETHREADDEMO_DIALOG};// NOTE: the ClassWizard will add data members here//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CSimpleThreadDemoDlg)protected:virtualvoidDoDataExchange(CDataExchange*pDX);// DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected:HICON m_hIcon;// Generated message map functions//{{AFX_MSG(CSimpleThreadDemoDlg)virtualBOOLOnInitDialog();afx_msgvoidOnSysCommand(UINT nID,LPARAM lParam);afx_msgvoidOnPaint();afx_msg HCURSOROnQueryDragIcon();afx_msgvoidOnButtonStart();afx_msgvoidOnButtonStop();afx_msgvoidOnDestroy();//}}AFX_MSGDECLARE_MESSAGE_MAP()};//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif// !defined(AFX_SIMPLETHREADDEMODLG_H__1FDB3406_48D0_44E7_9CE2_1977BCCA5492__INCLUDED_)

SimpleThreadDemoDlg.cpp

// SimpleThreadDemoDlg.cpp : implementation file//#include"stdafx.h"#include"SimpleThreadDemo.h"#include"SimpleThreadDemoDlg.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif// 线程参数结构体/////////////////////////////////////////////////////////////////////////////// CAboutDlg dialog used for App AboutclassCAboutDlg:publicCDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum{IDD=IDD_ABOUTBOX};//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtualvoidDoDataExchange(CDataExchange*pDX);// DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}voidCAboutDlg::DoDataExchange(CDataExchange*pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CSimpleThreadDemoDlg dialogCSimpleThreadDemoDlg::CSimpleThreadDemoDlg(CWnd*pParent/*=NULL*/):CDialog(CSimpleThreadDemoDlg::IDD,pParent){//{{AFX_DATA_INIT(CSimpleThreadDemoDlg)m_bStopThread=FALSE;// 不要停止m_bThreadActive=FALSE;// 线程不在运行m_hThread=NULL;//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);}voidCSimpleThreadDemoDlg::DoDataExchange(CDataExchange*pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CSimpleThreadDemoDlg)// NOTE: the ClassWizard will add DDX and DDV calls here//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CSimpleThreadDemoDlg,CDialog)//{{AFX_MSG_MAP(CSimpleThreadDemoDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_START,OnButtonStart)ON_BN_CLICKED(IDC_BUTTON_STOP,OnButtonStop)ON_WM_DESTROY()//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CSimpleThreadDemoDlg message handlersBOOLCSimpleThreadDemoDlg::OnInitDialog(){CDialog::OnInitDialog();// Add "About..." menu item to system menu.// IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX<0xF000);CMenu*pSysMenu=GetSystemMenu(FALSE);if(pSysMenu!=NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if(!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);}}// Set the icon for this dialog. The framework does this automatically// when the application's main window is not a dialogSetIcon(m_hIcon,TRUE);// Set big iconSetIcon(m_hIcon,FALSE);// Set small icon// TODO: Add extra initialization herereturnTRUE;// return TRUE unless you set the focus to a control}voidCSimpleThreadDemoDlg::OnSysCommand(UINT nID,LPARAM lParam){if((nID&0xFFF0)==IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID,lParam);}}// If you add a minimize button to your dialog, you will need the code below// to draw the icon. For MFC applications using the document/view model,// this is automatically done for you by the framework.voidCSimpleThreadDemoDlg::OnPaint(){if(IsIconic()){CPaintDCdc(this);// device context for paintingSendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);// Center icon in client rectangleintcxIcon=GetSystemMetrics(SM_CXICON);intcyIcon=GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);intx=(rect.Width()-cxIcon+1)/2;inty=(rect.Height()-cyIcon+1)/2;// Draw the icondc.DrawIcon(x,y,m_hIcon);}else{CDialog::OnPaint();}}// The system calls this to obtain the cursor to display while the user drags// the minimized window.HCURSORCSimpleThreadDemoDlg::OnQueryDragIcon(){return(HCURSOR)m_hIcon;}// 线程函数UINTCSimpleThreadDemoDlg::ThreadProc(LPVOID pParam){THREAD_PARAM*pThreadParam=(THREAD_PARAM*)pParam;CSimpleThreadDemoDlg*pDlg=pThreadParam->pDlg;TRACE("线程开始运行\n");// 执行5次循环for(inti=1;i<=5;i++){// 检查停止标志if(pDlg->m_bStopThread){TRACE("线程接收到停止信号\n");break;}// 执行工作pDlg->DoThreadWork(i);// 休眠1秒Sleep(1000);}// 线程结束,更新状态pDlg->m_bThreadActive=FALSE;// 清理参数deletepThreadParam;TRACE("线程运行结束\n");return0;}voidCSimpleThreadDemoDlg::DoThreadWork(intnIteration){TRACE("执行第%d项工作\n",nIteration);// 这里可以添加实际的工作代码}/////////////////////////////////////////////////////////////////////////////// 启动线程voidCSimpleThreadDemoDlg::OnButtonStart(){TRACE("=== 启动线程 ===\n");TRACE("=== 启动线程 ===\n");if(m_bThreadActive){AfxMessageBox("线程已经在运行");return;}// 重置事件if(m_hStopEvent){ResetEvent(m_hStopEvent);}// 初始化标志m_bStopThread=FALSE;// 不要停止m_bThreadActive=TRUE;// 线程正在运行// 创建线程参数// 创建线程参数THREAD_PARAM*pParam=newTHREAD_PARAM;pParam->pDlg=this;pParam->nCounter=0;// 创建线程(使用CREATE_SUSPENDED,确保完全初始化后再运行)CWinThread*pThread=AfxBeginThread(ThreadProc,pParam,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);if(pThread==NULL){AfxMessageBox("创建线程失败");m_bThreadActive=FALSE;deletepParam;return;}// 保存句柄m_hThread=pThread->m_hThread;// 恢复线程运行pThread->ResumeThread();TRACE("线程启动成功,ID: %d\n",pThread->m_nThreadID);AfxMessageBox("线程已启动");}/////////////////////////////////////////////////////////////////////////////// 停止线程voidCSimpleThreadDemoDlg::OnButtonStop(){TRACE("=== 停止线程 ===\n");if(!m_bThreadActive){AfxMessageBox("没有正在运行的线程");return;}// 安全终止线程SafeTerminateThread();AfxMessageBox("线程已停止");}voidCSimpleThreadDemoDlg::SafeTerminateThread(){TRACE("安全终止线程\n");if(!m_bThreadActive){TRACE("线程未激活\n");return;}// 1. 设置停止标志和事件m_bStopThread=TRUE;if(m_hStopEvent){SetEvent(m_hStopEvent);}// 2. 等待线程正常结束if(m_hThread){TRACE("等待线程正常退出...\n");// 等待3秒让线程正常退出DWORD dwWaitResult=WaitForSingleObject(m_hThread,3000);if(dwWaitResult==WAIT_OBJECT_0){TRACE("线程正常退出\n");}elseif(dwWaitResult==WAIT_TIMEOUT){TRACE("线程超时未退出,尝试强制终止\n");// 3. 强制终止(最后手段)// 警告:这可能导致资源泄漏,只在必要时使用if(!TerminateThread(m_hThread,0)){TRACE("强制终止失败,错误代码: %d\n",GetLastError());}else{// 等待线程完全终止WaitForSingleObject(m_hThread,1000);TRACE("线程已被强制终止\n");}}// 4. 关闭句柄CloseHandle(m_hThread);m_hThread=NULL;}// 5. 重置状态m_bThreadActive=FALSE;m_bStopThread=FALSE;TRACE("安全终止线程完成\n");}voidCSimpleThreadDemoDlg::OnDestroy(){TRACE("=== 窗口销毁处理开始 ===\n");// 确保线程结束SafeTerminateThread();CDialog::OnDestroy();TRACE("=== 窗口销毁处理结束 ===\n");}CSimpleThreadDemoDlg::~CSimpleThreadDemoDlg(){// 确保线程结束if(m_bThreadActive&&m_hThread){// 设置停止事件SetEvent(m_hStopEvent);// 等待线程结束,最多等待5秒DWORD dwWait=WaitForSingleObject(m_hThread,5000);if(dwWait==WAIT_TIMEOUT){// 如果线程在5秒内没有结束,强制终止TerminateThread(m_hThread,0);TRACE("线程被强制终止\n");}// 关闭句柄CloseHandle(m_hThread);m_hThread=NULL;}// 关闭事件句柄if(m_hStopEvent){CloseHandle(m_hStopEvent);m_hStopEvent=NULL;}}

Debug模式运行

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 11:26:47

null有索引和没索引怎么存储?

1.如果有索引&#xff0c;那么存储在二级索引中,聚集存储在同一个或者相邻的索引页,例如:[(null,id1)(null,id2)] 2.如果没有索引,那么存储在主键索引行数据中,例如:(id1,namenull,pwd123),(id2,namenull,pwd456)

作者头像 李华
网站建设 2026/4/23 12:54:54

基于定子磁场矢量控制的异步电机磁链观测模型研究与应用

基于定子磁场定向矢量控制的异步电机磁链观测模型电机控制算法里有句老话&#xff1a;磁链准不准直接决定系统能不能转。今天咱们聊聊异步电机定子磁场定向下的磁链观测&#xff0c;这玩意儿就像给电机装了个X光机&#xff0c;看不见的磁场分布全靠它来透视。先上点硬核代码镇楼…

作者头像 李华
网站建设 2026/4/23 14:13:14

从“经验浪费”到“资产变现”:AI时代IT人最值钱的能力,是把个人经验变成可复用的“智能资产”

前阵子参加政务IT行业交流会&#xff0c;听到一个扎心的现象&#xff1a;同一家公司的两个技术团队&#xff0c;同时接了市级政务服务中心的“一网通办”定制项目。A团队花了3个月才交付&#xff0c;还因为“没考虑跨部门数据共享的合规要求”反复返工&#xff1b;B团队只用1个…

作者头像 李华
网站建设 2026/4/23 12:59:08

13. django中间件

1、概述 AOP(Aspect Oriented Programming)&#xff0c;面向切面编程&#xff0c;是对业务逻辑的各个部分进行隔离&#xff0c;从而使得业务逻辑各部分之间的耦合度降低&#xff0c;提高程序的可重用性&#xff0c;同时提高了开发的效率。可以实现在不修改源代码的情况下给程序…

作者头像 李华