在用visual studio进行界面编程时(如MFC),前台UI我们能够通过MFC的消息循环机制实现。而对于后台的数据处理。我们可能会用到多线程来处理。

那么对于大多数人(尤其是我这样的菜鸟),一个比較快捷的方法便是选择MFC多线程:AfxBeginThread或者CreateThread来进建立多线程。当一两个线程还是能够得。当有3个或者3个以上的线程出现时,极可能出现内存泄漏。原因分析例如以下:

CWinThread的多线程不安全性:

由于 CWinThread 会调用_beginthreadex来初始化C执行时库。而相同地,假设线程被强制终止(TerminateThread),由于  TerminateThread是不会去管 C执行时库的,从而,导致部分和引用计数相关的C执行时数据的内存释放出现故障。最典型的特征是,使用STL库的静态变量
内存回收将出错,从而导致进程退出时误报异常。

此外,假设AfxBeginThread频繁进行回收和分配线程,假设不严格操作,也会导致崩溃。

VC6中,应该严格控制STL库的使用,避免MFC库和STL库并存,否则,会有非常多问题。

原因:

AfxBeginThread在内部直接调用了CreateThread创建线程而不是c语言下推荐的beginthreadex函数,而这两个函数是有差别的,主要是c执行库的历史遗留问题造成的。

在多线程环境中存在问题的C/C++执行期库变量和函数包含errno、_doserrno、strtok、_wcstok、strerror、_strerror、tmpnam、tmpfile、asctime、_wasctime、gmtime、_ecvt和_fcvt等。

若要使多线程C/C++程序可以正确地执行,必须创建一个数据结构,并将它与使用C/C++执行期库函数的每一个线程关联起来。当你调用C / C + +执行期库时,这些函数必须知道查看调用线程的数据块,这样就不会对别的线程产生不良影响。

那么系统是否知道在创建新线程时分配该数据块呢?回答是它不知道。系统根本不知道你得到的应用程序是用C/C++编写的。也不知道你调用函数的线程本身是不安全的。问题在于你必须正确地进行全部的操作。

若要创建一个新线程。绝对不要调用操作系统的CreateThread函数。必须调用C/C++执行期库函数_beginthreadex。

以下是关于_beginthreadex的一些要点:

      每一个线程均获得由C/C++执行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位于Mtdll.h文件里的Visual C++源码中)。传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。

传递给该函数的參数也保存在该数据块中。

_beginthreadex确实从内部调用CreateThread,由于这是操作系统了解怎样创建新线程的唯一方法。###能够看出调用_beginthreadex时分配了额外的内存空间。



    假设调用CreateThread,而不是调用C / C + +执行期库的_beginthreadex来创建新线程,将会发生什么情况。当一个线程调用要求tiddata结构的C / C + +执行期库函数时,将会发生以下的一些情况(大多数C / C + +执行期库函数都是线程安全函数,不须要该结构)。



先。 C / C + +执行期库函数试图(通过调用TlsGetValue)获取线程的数据块的地址。

假设返回

NULL作为tiddata块的地址。调用线程就不拥有与该地址相关的tiddata块。这时,C / C + +执行期库函数就在现场为调用线程分配一个tiddata块,并对它进行初始化。然后该tiddata块(通过TlsSetValue)与线程相关联。

###_beginthreadex相相应的推出函数是_endthreadex,这个函数会释放tiddata的内容。

---------------------------

    假设你採用CreateThread创建线程。而你没有使用上面所提到的那些特殊执行期库的话,也是不会出现故障的。假设一定要用那些执行库的话就最好调用_beginthreadex 这个api来创建线程,否则tiddata数据块就无法撤销,引起内存泄漏。

你能够參照_beginthreadex源码来进行理解。

引申阅读:

关于_beginthreadex和CreateThread的差别


最新文章

  1. 使用rsync同步文件
  2. 理解 Linux 网络栈(3):QEMU/KVM + VxLAN 环境下的 Segmentation Offloading 技术(发送端)
  3. Mac & XCode 使用技巧总结
  4. JS开发HTML5游戏《神奇的六边形》(二)
  5. [物理学与PDEs]第2章习题参考解答
  6. SQL Server 2005中的分区表(四):删除(合并)一个分区(转)
  7. maven3实战之仓库(快照版本)
  8. 七:zookeeper与paxos的分析
  9. mysql系统表加trigger和对特定的库禁用 DDL 语句
  10. python中数据的保存
  11. java并发 使用ScheduledExecutor的温室控制器--thinking in java 21.7.5
  12. HDU 5478 Can you find it(数学问题)
  13. POJ1850 组合数学
  14. 简单的UIScrollView 下拉刷新
  15. PMP和PRINCE2应该选择哪个?光环国际项目管理认证
  16. sqlmap详细使用 [精简]
  17. node.js之express框架入门篇
  18. centos6.5 yum update 报错Couldn't resolve host 'centos.ustc.edu.cn'
  19. python基础二(基础数据类型)
  20. redis的数据持久化方案

热门文章

  1. java与.net比较学习系列(5) 流程控制语句
  2. HTTP协议2之基本认证--转
  3. EffectiveC#6--区别值类型数据和引用类型数据
  4. .NET winform 的keypress事件中判断当用户按下的是哪个键
  5. 从C# String类理解Unicode(UTF8/UTF16)
  6. 我的django之旅(一)
  7. 【Solr专题之九】SolrJ教程
  8. < meta http-equiv = "X-UA-Compatible" content = "IE=edge,chrome=1" />的作用
  9. java直接打开pdf,doc,xls
  10. __m128i的理解[转]