终止线程 
有两种情况可以使线程结束:控制函数结束或者根本就不允许线程完成,而提前终止它。我们可以想象在WORD中进行后台打印,如果打印结束了,那线程就可以结束了。如果用户中止了打印,那后台打印线程也要终止了。本文将主要介绍对这两种情况的实现,并且介绍如何获得线程的结束代码。

1.对于工作线程,结束它是比较容易的:退出线程函数然后返回一个结束原因的代码就是了。用户可以使用AfxEndThread函数或直接利用return返回。通常0代表成功返回,这不是硬性规定,一切要取决于你了。对于用户界面线程,调用::PostQuitMessage,它所要的唯一的参数就是返回代码,也就是工作线程中的那个码,性质是一样的。0通常代表成功。

2.提前终止一个线程也不难:在线程函数中调用AfxEndThread就是了,其中要传入的参数就是返回代码。这会停止线程的执行,释放线程栈,及与线程相关的DLL,并从内存中删除线程对象。AfxEndThread必须在线程函数内调用,如果用户希望从一个线程结束另一个线程,则需要在两个线程间建立通信机制。

如果需要获得线程返回代码,只需要调用::GetExitCodeThread就可以了。这个函数的具体作用就看大家具体去查帮助了。它传入的是线程的句柄,和一个提向返回代码的指针。将来就从那个指针得到返回代码。如果线程仍然处于活动状态,那么::GetExitCodeThread得到的返回代码为STILL_ACTIVE,如果已经退出则得到的是返回代码的地址。获得CWinThread对象的返回代码还需要一点麻烦,通常,当CWinThread线程结束时,线程对象就删除了,因为这个对象不存在了,也就没有办法访问对象的m_hThread变量了,为了避免这种情况,可以有两种方法:

将m_bAutoDelete设置为FALSE,这使得线程结束后CWinThread对象仍然存在,这样用户就可以访问m_hThread了,但是如果用户使用这种方法,用户需要自己析构CWinThread对象。这种方法是推荐的方法。

下一个方法是另外保存线程的句柄。在线程创建后,将m_hThread保存在另一个变量中,以后访问这个变量就是了。但是要小心,在复制句柄以前线程并没有结束,最安全的方法是在AfxBeginThread中传入CREATE_SUSPENDED,保存句柄,然后通过调用ResumeThread,重新开始线程。这两种方法都可以帮助用户得到CWinThread对象的返回代码。

对于Worker线程,终止线程可以使用线程的退出码作为返回值从线程函数返回。

对于UI线程,因为有消息循环,需要发送一个WM_QUIT消息到线程的消息队列,当线程接收到WM_QUIT消息时退出消息循环。因此,结束线程可以在线程内部调用SDK的PostQuitMessage函数,发送WM_QUIT消息。
PostQuitMessage函数的定义如下:

void PostQuitMessage(int nExitCode);

其中:

nExitCode:线程的退出码。

MFC还提供了AfxEndThread函数,Worker线程和UI线程都可以通过在线程内部调用AfxEndThread函数结束线程。

AfxEndThread函数的定义如下:

void AfxEndThread(UINT nExitCode, BOOL bDelete = TRUE);

其中:

nExitCode:线程的退出码。

在MFC的THRDCORE.CPP中,AfxEndThread函数的相关代码如下:

// THRDCORE.CPP
void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete)
{// remove current CWinThread object from memoryAFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();CWinThread* pThread = pState->m_pCurrentWinThread;if (pThread != NULL){ASSERT_VALID(pThread);ASSERT(pThread != AfxGetApp());// cleanup OLE if requiredif (pThread->m_lpfnOleTermOrFreeLib != NULL)(*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);if (bDelete)pThread->Delete();pState->m_pCurrentWinThread = NULL;}// allow cleanup of any thread local objectsAfxTermThread();// allow C-runtime to cleanup, and exit the thread_endthreadex(nExitCode);
}

从MFC代码中可以看出,AfxEndThread函数通过调用_endthreadex函数终止线程。此外,函数还进行释放线程的堆栈、删除线程对象等工作。

如果在其它线程中终止该线程,必须采用线程通信的方法实现。其中一种简单的方法是建立一个变量,让线程监视该变量,当该变量为某个值时,则终止线程。

(1)创建1个基于对话框的应用程序,名称为Demo。

(2)在IDD_DEMO_DIALOG对话框资源中添加控件,如表所示。

类型 ID 标题
Static IDC_STATIC 数据:
Edit IDC_DATA  
Button IDC_BEGIN_THREAD 启动线程
Button IDC_END_THREAD 终止线程

(3)在文件中定义线程传递参数的数据结构,代码如下:

// DemoDlg.h
typedef struct THREAD_PARAM
{HWND hWnd;int nData;BOOL bExit;
}_THREAD_PARAM;

(4)在CDemoDlg类中添加成员变量,代码如下:

// DemoDlg.h
protected:CWinThread* m_pThread;THREAD_PARAM m_ThreadParam;

(5)在CDemoDlg类的构造函数中初始化成员变量,代码如下:

// DemoDlg.cpp
CDemoDlg::CDemoDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDemoDlg::IDD, pParent)
{// ...m_pThread = NULL;m_ThreadParam.nData = 0;
}

(6)在CDemoDlg类的OnInitDialog函数中添加如下代码:

// DemoDlg.cpp  BOOL CDemoDlg::OnInitDialog()
{CDialog::OnInitDialog();// …SetDlgItemInt(IDC_DATA, m_nData);return TRUE;
}

(7)在文件中定义线程消息,代码如下:

// DemoDlg.h
#define WM_THREADMSG WM_USER+1

(8)在文件中定义线程函数,代码如下:

// DemoDlg.h
UINT ThreadProc(LPVOID pParam);
// DemoDlg.cpp
UINT ThreadProc(LPVOID pParam)
{//线程参数THREAD_PARAM* pThreadParam = (THREAD_PARAM*)pParam;while (!pThreadParam->bExit){Sleep(100);pThreadParam->nData++;//向主线程窗口发送消息::PostMessage(pThreadParam->hWnd, WM_THREADMSG, 0, 0);}return 0;
}

(9)在CDemoDlg类中分别为Button控件添加BN_CLICKED添加消息处理函数,代码如下:

// DemoDlg.cpp
void CDemoDlg::OnBeginThread()
{if (m_pThread != NULL){AfxMessageBox(_T("线程已经启动。"));return;}m_ThreadParam.hWnd = m_hWnd;m_ThreadParam.bExit = FALSE;//启动线程,初始为挂起状态m_pThread = AfxBeginThread(ThreadProc, &m_ThreadParam,THREAD_PRIORITY_ABOVE_NORMAL, 0, CREATE_SUSPENDED);//线程结束时不自动删除m_pThread->m_bAutoDelete = FALSE;//恢复线程运行m_pThread->ResumeThread();
}void CDemoDlg::OnEndThread()
{if (m_pThread == NULL){AfxMessageBox(_T("线程已经终止。"));return;}m_ThreadParam.bExit = TRUE;//等待线程结束::WaitForSingleObject(m_pThread->m_hThread, INFINITE);delete m_pThread;m_pThread = NULL;
}

(10)在CDemoDlg类中添加自定义消息处理函数,代码如下:

// DemoDlg.h
afx_msg LRESULT OnMsgFunc();// DemoDlg.cpp
BEGIN_MESSAGE_MAP(CDemoDlg, CDialog)ON_MESSAGE(WM_THREADMSG, OnMsgFunc)
END_MESSAGE_MAP()LRESULT CDemoDlg::OnMsgFunc()
{SetDlgItemInt(IDC_DATA, m_ThreadParam.nData);return 1;  
}

安全终止MFC线程全相关推荐

  1. MFC 线程的退出方法

    A.线程函数的返回(推荐用法)(需要考虑的是catch/运行标志/错误处理等方法) B.ExitThread函数(不推荐) C.同一个进程或者另一个进程中的线程调用TerminateThread函数( ...

  2. Java终止当前线程的方法

    2019独角兽企业重金招聘Python工程师标准>>> 在系统开发中常常设计到多线程的使用,正常需求下开启线程不需要中途停止,特殊需求下需要停止当前线程(我当前的网页爬取系统中用到, ...

  3. 【C/C++多线程编程之四】终止pthread线程

    多线程编程之终止pthread线程 Pthread是 POSIX threads 的简称,是POSIX的线程标准.           终止线程似乎是多线程编程的最后一步,但绝不是本系列教材的结束.线 ...

  4. python结束线程_2018-01-02 如何优雅地终止python线程

    前言 · 零 我们知道,在python里面要终止一个线程,常规的做法就是设置/检查 --->标志或者锁方式来实现的. 这种方式好不好呢? 应该是不大好的!因为在所有的程序语言里面,突然地终止一个 ...

  5. 如何quot;优雅quot;地终止一个线程?

    转载自 如何"优雅"地终止一个线程? 我们的系统肯定有些线程为了保证业务需要是要常驻后台的,一般它们不会自己终止,需要我们通过手动来终止它们.我们知道启动一个线程是start方法, ...

  6. java并发编程之正确地终止一个线程interrupt/interrupted

    以下demo是错误的终止线程的demo(使用thread.stop()方法实现终止线程): public class ErrorStopThreadDemo {public static void m ...

  7. java 线程退出cmd_java 线程的终止与线程中断

    关于线程终止: 1.一般来讲线程在执行完毕后就会进入死亡状态,那该线程自然就终止了. 2.一些服务端的程序,可能在业务上需要,常驻系统.它本身是一个无穷的循环,用于提供服务.那对于这种线程我们该如何结 ...

  8. 终止运行线程的注意事项

    终止运行线程 1. 线程函数返回. 2. 线程通过调用ExitThread函数"杀死"自己(避免使用). 3. 同一个进程或另一个进程中的线程调用TerminateThread函数 ...

  9. 如何终止Java线程

    Thread.stop,Thread.suspend,Thread.resume,Runtime.runFinalizersOnExit都已经被废弃了. 为什么要废弃Thread.stop?因为此函数 ...

最新文章

  1. 成功有感之给年轻人的10个忠告
  2. bzoj1013球形空间
  3. webbench源码解析
  4. gitbook安装与使用之windows下搭建gitbook平台
  5. 驾校约车html网站源码,html5首汽约车微信感恩活动页面模板
  6. 结对-五子棋游戏-测试过程
  7. web myeclipse为什么连接不上css_好程序员web前端培训分享:web前端自学该怎么规划学习...
  8. 使用Cloudflare API动态解析域名IP
  9. 搜索关键词,生成云图
  10. c#设置导出Excel的列宽
  11. Halcon union_straight_contours_xld详解
  12. BZOJ 1776: [Usaco2010 Hol]cowpol 奶牛政坛 贪心lca/点分治
  13. switch手柄键位名称图解_Switch官方资料汇总!所有你想知道的都在这里
  14. 王者荣耀虚拟服务器设置方法,《王者荣耀》s22最佳系统设置教程攻略 s22设置如何调...
  15. 本地安装kylin学习环境
  16. fake rolex watches sale Stuff.co.nz - 新西兰最新新闻和世界新闻,体育新闻和天气预报新西兰
  17. APS排程软件自动分配任务到多台机台同时生产
  18. ansys,单元体转换以及如何查看当前单元体的类型,一些指令讲解。
  19. iTerm2终端工具在Mac OS上使用详解
  20. QT制作一个图片播放器

热门文章

  1. iptables(上)
  2. android pc模拟器哪个好,安卓模拟器电脑版哪个好用
  3. sql server配置连接oracle数据库,MS SQL Server连接Oracle
  4. java windows系统监控_Windows资源监控工具大全
  5. python numpy安装教程_手把手教你搭建机器学习开发环境—Python与NumPy的超简安装教程...
  6. java 中的servlet_java中的Servlet
  7. google提供的adb工具包_开源化学信息学工具包(Open Access Cheminformatics Toolkits)
  8. 人脸识别技术如何应用到美颜领域?
  9. xilinx FPGA的远程更新(动态加载)详解(Using a Microprocessor to Configure 7 Series FPGAs)
  10. flutter图片预览_Flutter 视频缩略图