前言:

  近日在网上看到很多人问及如何关闭一下线程,但是我看网上给出的并不详细,而且有些方法还是错误的。小弟在此拙作一篇,不谈别的,只谈及如何正确的关闭MFC的线程,至于Win32和C RunTime的线程暂不涉及。

一.关于MFC的线程

  1.MFC的线程有两种,一种称为Work线程,一种称为UI线程。一般情况下Work线程与UI线程的区别主要在于UI线程有消息队列(并不是有没有界面,这点要注意,UI线程也是可以没有界面的)。

  2.创建这两种线程的区别也不大,可以从创建函数看出。

[cpp] view plaincopyprint?
  1. // Work线程
  2. CWinThread* AfxBeginThread(
  3. AFX_THREADPROC pfnThreadProc,
  4. LPVOID pParam,
  5. int nPriority = THREAD_PRIORITY_NORMAL,
  6. UINT nStackSize = 0,
  7. DWORD dwCreateFlags = 0,
  8. LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
  9. );
  10. // UI线程
  11. CWinThread* AfxBeginThread(
  12. CRuntimeClass* pThreadClass,
  13. int nPriority = THREAD_PRIORITY_NORMAL,
  14. UINT nStackSize = 0,
  15. DWORD dwCreateFlags = 0,
  16. LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
  17. );

// Work线程 CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ); // UI线程 CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

关于函数的具体使用,请查阅MSDN,这里不涉及。

二. 结束线程前的注意事项

  在结束一个线程前,只有一点要注意,那就是m_bAutoDelete 的状态。(什么?不知道m_bAutoDelete ?!!快去查阅MSDN吧)。

[c-sharp] view plaincopyprint?
  1. m_bAutoDelete = FALSE; // 表示你自己管理 CWind 对象,包括它的清理
  2. m_bAutoDelete = TRUE;  // 默认值, 系统会自己清理 CWind 对象

m_bAutoDelete = FALSE; // 表示你自己管理 CWind 对象,包括它的清理 m_bAutoDelete = TRUE; // 默认值, 系统会自己清理 CWind 对象

m_bAutoDelete = TRUE; 系统自己清理CWind对象,当然还包括CloseHandle(),ExitInstance()等等一堆函数的调用。

m_bAutoDelete = FALSE; 那么就一定要记得自己在用完后调用delete删除创建线程的对象,这一点极为重要,因为不调用delete一定会有内存泄漏问题。

总之m_bAutoDelete 的值对结束工作是很重要的,这点一定要注意。

三.正确的结束一个Work线程

  因为Work线程是一个全局函数,或者是一个Static函数,所以它的运行完成也就是它的正常退出了。(什么?不明白,示例代码如下)

  1.情况一:

[c-sharp] view plaincopyprint?
  1. UINT WorkFunc(LPVOID pParam)
  2. {
  3.   // 工作
  4.   ......
  5. return 0;  // 就算正常退出了,简单吧
  6. }

UINT WorkFunc(LPVOID pParam) { // 工作 ...... return 0; // 就算正常退出了,简单吧 }

  2.情况二:

Work线程是个死循环或一时半会儿出不来,这时要主线程要发个消息给Work线程,让他退出。

[cpp] view plaincopyprint?
  1. UINT WorkFunc(LPVOID pParam)
  2. {
  3. for(;;)
  4. {
  5. // ...
  6.   if( WAIT_OBJECT_0 == WaitForSingleObject(m_hThread, INFINITE)} // 收到激发态的消息
  7. {
  8. return 0;//正常退出
  9. }
  10.  }//end for
  11.   
  12.  return 0;
  13. }

UINT WorkFunc(LPVOID pParam) { for(;;) { // ... if( WAIT_OBJECT_0 == WaitForSingleObject(m_hThread, INFINITE)} // 收到激发态的消息 { return 0;//正常退出 } }//end for return 0; }

关于主线程发一个激发态的消息给Work线程,有多种方法,如在主线程里调用SetEvent()等等,你想用什么都行,但是最好不要在Work线程里用Busy loop的方法。至于为什么,请参阅《Win32多线程程序设计》上面的论述。

四.正确结束一个UI线程

  因为UI线程有消息队列,所以结束一个UI线程最好的方法是发一个WM_QUIT消息给消息队列,方法很多如:PostQuitMessage(),PostThreadMessage()等等。但是发出消息后最好等待看UI线程是否已经退出(很多人都没有提及这一点,但是实际工作中发现,加上这一点是多么的重要)。

[c-sharp] view plaincopyprint?
  1. // 主线程结束UI线程的代码
  2. if(pThread)
  3. {
  4. // 1. 发一个WM_QUIT 消息结 UI 线程
  5. pThread->PostThreadMessage(WM_QUIT, NULL, NULL);
  6. // 2. 等待 UI 线程正常退出
  7. if (WAIT_OBJECT_0 == WaitForSingleObject(pThread->m_hThread, INFINITE))
  8.  {
  9. // 3. 删除 UI 线程对象,只有当你设置了m_bAutoDelete = FALSE; 时才调用
  10.   delete   pThread;
  11.  }
  12. }

// 主线程结束UI线程的代码 if(pThread) { // 1. 发一个WM_QUIT 消息结 UI 线程 pThread->PostThreadMessage(WM_QUIT, NULL, NULL); // 2. 等待 UI 线程正常退出 if (WAIT_OBJECT_0 == WaitForSingleObject(pThread->m_hThread, INFINITE)) { // 3. 删除 UI 线程对象,只有当你设置了m_bAutoDelete = FALSE; 时才调用 delete pThread; } }

五.关于几个问题的解答

1.问:为什么我的UI线程没有调用ExitInstance()?

  答:最大的可能是你的WM_QUIT消息没有通知到UI线程。为了保险期间最好调用PostThreadMessage(),这样可以指定线程的ID。当然如果你对消息比较熟悉的话,也可以抛一个消息到最顶层。

2.问:为什么我的UI线程没有调用析构函数?

  答:检查看你的m_bAutoDelete = FALSE,如果是的话,那么看你的线程对象是否已经delete了。一般情况下调用delete会调用析构函数。

3.问:在UI线程中没有调用WaitForSingleObject(),会怎么样?

  答:我们知道在PostMessage()之后,函数会马上返回,如查没有wait...(),那么紧接着就调用了delete,很有可能对象做的退出操作过程还没有完成时,又把对象delete掉了,结果还是没有正常结束。(注:WM_QUIT消息之后会触发一堆函数,这个时间是不定的,所以最好Wait...才是正道。)

六.最后不愿提的函数

  几乎每本讲线程的书都会提到下面的函数:

  void AfxEndThread(UINT nExitCode);

  TerminateThread();

  ......还有其它的一些极端的函数

我的观点是:最好不要使用,除非你知道要发生什么!!

如何正确的关闭 MFC 线程相关推荐

  1. Java并发 正确终止与恢复线程

    为什么80%的码农都做不了架构师?>>>    前面提到了stop().suspend()等方法在终止与恢复线程的弊端,那么问题来了,应该如何正确终止与恢复线程呢?这里可以使用两种方 ...

  2. 如何正确的停掉线程?这里面大有门道!

    点击关注公众号,实用技术文章及时了解 来源:https://blog.csdn.net/weixin_29729247 目录 为什么不强制停止 如何用 interrupt 停止线程 sleep 期间能 ...

  3. tomcat关闭后线程依然运行解决办法

    tomcat关闭后线程依然运行解决办法,设置线程为守护线程 守护线程与非守护线程 最近在看多线程的Timer章节,发现运用到了守护线程,感觉Java的基础知识还是需要补充. Java分为两种线程:用户 ...

  4. clocks_per_sec 时间不正确_壁挂炉不用了怎么关?壁挂炉正确的关闭方法

    天气火热,用壁挂炉取暖的用户也都很想了解怎么正确关掉暖气.用过壁挂炉的用户都知道,它不但能采暖,还能提供生活热水,在天气转暖的时候,有些只想单独关闭暖气功能,还有的是暖气和热水功能都不用了,那怎么来正 ...

  5. 【Elasticsearch】如何正确的关闭 重启 Elasticsearch集群

    文章目录 1.背景 2.问题原因 3.ES内存数据模型 4.如何正确的关闭ES或者ES集群 4.1 第一步,禁止分片自动分布 4.2 如何启动ES集群 5.ElasticSearch服务快速重启操作步 ...

  6. BOOST 线程完全攻略 - 扩展 - 可被关闭的线程类

    2019独角兽企业重金招聘Python工程师标准>>> 本文假设读者已经基本了解boost线程库的使用方法. boost是个开源工程,线程这一块也在不断完善之中,到现在这个阶段,bo ...

  7. MFC::error C2065: “IDD_DIALOG1”: 未声明的标识符 MFC线程中发送与处理自定义消息

    添加资源头文件就行. #include "Resource.h" MFC线程中发送消息 1.先写义好接收 #define WM_SET_FOCUS WM_USER+100 //自定 ...

  8. 正确及时关闭数据库连接

    1.1  概述 在JAVAEE后台编码时,时常出现没有正确及时关闭数据库连接资源(Connection,Statement, ResultSet)现象,导致程序运行过程中出现意想不到的错误. 本文档首 ...

  9. MFC线程创建运行关闭的问题

    最近,由于论文的需求,要用到Windows下的多线程.考虑到界面用MFC写 了,于是上网搜了下MFC下的多线程怎样搞,都说用AfxBeginThread来日比较好.哥向来比较浮躁,先搜搜有没相关代码, ...

最新文章

  1. Bzoj3168 [Heoi2013]钙铁锌硒维生素
  2. Helm包管理工具(简介、安装、方法)
  3. 第五章:管理数据库存储结构
  4. js的apply方法使用详解,绝对NB
  5. 早该改了,只是我们太穷了
  6. 梯度下降优化方法'原理_优化梯度下降的新方法
  7. sql date类型_共享单车数据分析的SQL数据库设计
  8. aspell_如何使用Aspell在Linux命令行上检查拼写
  9. Android权限管理之Permission权限机制及使用
  10. Linux 内核 3.8 是给 Linux 用户的圣诞礼物
  11. 计算机程序设计里的奇书
  12. 适配器模式之备忘录模式
  13. 迅为IMX6ULL开发板Linux系统移植-NXP官方Linux源码编译
  14. 动手编写操作系统(1):初识Bochs
  15. 电脑键盘部分按键失灵_键盘按键失灵别担心 电脑达人教你几步解决方法
  16. Java Access Bridge
  17. 国开计算机实操题操作,国开大学计算机实操答案一.
  18. 2018 Google IO大会来了
  19. 【Django】uWSGI和Gunicorn【转】
  20. SQI SERVER2016安装选项

热门文章

  1. php echo 大括号,PHP中echo输出中存在括号()的处理
  2. java环绕通知的应用_Spring之环绕通知
  3. NYOJ-过河问题(贪心)
  4. 如何建立MFC绘图工程:外貌框架_基于对话框(开发平台VS2017)
  5. 一次Python性能调优经历
  6. Coursera机器学习编程作业Python实现(Andrew Ng)—— 2.1 Logistic Regression
  7. 双网卡centos7 iptables防火墙与/etc/rc.d/rc.local开机运行
  8. MySQL-Proxy实现MySQL读写分离
  9. 《Java编码指南:编写安全可靠程序的75条建议》—— 指南16:避免授予过多特权...
  10. mysql 协议的processInfo命令包及解析