C++多线程调试和测试的注意事项

  今天顺便说一下开发C++多线程应用程序时,有关调试和测试的一些注意事项。下面这些注意事项主要是针对C++,不过有些对于其它的语言也适用。

  关于设置断点和单步执行

  很多同学非常依赖于调试器的断点功能和单步功能。这在单线程情况下倒还好(不过有些单线程但涉及GUI的程序,也会有点麻烦)。至于多线程程序的调试,这两种手段简直就是噩梦的开始。多线程造成的主要问题大都和竞态条件(Race Condition,详细解释看“这里”)有关。而设置断点或单步跟踪可能会严重干扰多线程之间的竞争状态。导致你看到的是一个假象。比如本来有两个线程并发执行,存在某些不和谐的Bug(由竞态引起)。一旦你在某一个线程设置了断点,该线程在断点处停住了,只剩下另一个线程在跑。这时候,并发的场景已经完全被破坏了,你通过调试器看到的可能是一个和谐的场景。

  稍微跑一下题。这很类似量子力学的“测不准原理”,观测者的观测行为干扰了被测量的客体,导致观测者看到的是一个干扰后的现象。

  关于Log输出

  既然断点和单步不好用。那咋办捏?一个替代方案是输出log日志。它可以有效减轻断点和单步所导致的(针对竞态条件的)副作用。

  传统Log机制的问题

  传统的log输出主要是打印到屏幕或者输出到文件。对于C++而言,标准库内置的类和函数(比如cout、printf、fputs)可能会有线程安全 的问题(和编译器的具体实现有关)。尤其是标准流类库(iostream)的八个全局对象,更是要小心慎用。轻则输出的log文本混杂,重则导致程序崩 溃。

  鉴于上述原因,应该尽量使用第三方线程库内置的log机制来搞定log输出功能。比如ACE内置的ACE_Log_Msg等。

  Log函数要短小精悍

  很多情况下,我们会包装一个公用的函数来实现log输出功能。然后在该函数内部调用线程库的log类/函数。为了不影响线程的竞态条件,这个log函数要尽可能简单轻便:不要涉及太多杂七杂八的琐事、千万别进行耗时的操作、尽量不操作一些全局的变量。

  Log的副作用

  不过捏,即使log函数再短小精悍,也还是有可能影响竞态条件(毕竟log也有开销,也要消耗CPU时间)。

  万一竞态条件受到log的影响,那就比较棘手了。我以前就碰到过这种情况:加了log,程序没有问题;去掉log,程序随机崩溃。这种情况一般有两种可能:要么是log功能本身有问题,要么是程序的竞态条件非常敏感(连log的开销都会有影响)。

  这时候你能依靠的就只有肉眼和人脑了。先把相关的代码和文档仔细看上几遍(最好再找其他有经验的人一起Code Review),然后大家一起开动脑筋使劲琢磨。

  关于Debug版本和Release版本

  C++程序经常有Debug版本和Release版本的区别。有些时候,这也会导致一些多线程的问题。

  由于Debug版本包含了一些调试信息、启用了某些调试机制(比如assert宏)。所以就可能影响到多线程的竞争状态。在倒霉的时候,会碰上Debug版本工作正常,Release版本程序随机崩溃。要避免这种情况,可以考虑下面两个办法:

  放弃使用Debug版本

  你可以干脆放弃使用Debug版本。在这种情况下,你需要考虑把诸如assert之类调试相关的宏替换成自己的一套宏,使得在非Debug版本下也可以生效。

  两种版本同步测试

  使用此方法,程序员平时自测可以使用Debug版本,但是测试人员日常测试的必须是Release版本。具体的操作步骤可以利用每日构建来辅助进行(每日构建的介绍参见“这里”)。一定要避免:在平时仅仅搞Debug版本的测试,等到发布前夕再制作Release版本。这种做法是非常危险的!

  关于测试的机器(硬件)

  说一个亲身经历、印象深刻的事情。

  当年用ACE开发跨平台程序的时候,公司内的的开发环境和测试环境都是单CPU的机器。因为当时多核的机器还没有面世,多CPU的机器又挺贵,公司没舍得花钱配置。

  软件开发完之后,测试人员经过几轮回归测试,也没发现太大问题。但是拿到客户的环境中运行,却经常会随机性崩溃。因为不能在客户环境中Debug,自己 的环境又死活没问题,开发组的几个人只好充分发挥肉眼和人脑的功能(盯着代码和设计文档猛想)。经过N长时间,差点把脑袋想破,最后才意识到客户的机器是 多CPU的。然后赶紧从其它部门借了一台多CPU机器,装上软件调试,最后查出是一个第三方库有问题。此事过后,我立即想出各种法子,去申请了几台多 CPU机器给测试人员用。

  由于上述的前车之鉴,所以我强烈建议:如果是开发多线程的应用程序,尽量给每一个编程人员和测试人员都配置多核/多CPU的机器。毕竟现在多核机器已经很普及了,即使多CPU的机器,价格也还凑合。实在没必要为了省那点小钱而引入开发风险(不光会浪费开发/测试人员的时间,还可能增加实施和维护的成本)。

  另外,可能有同学会问“超线程的机器如何捏?”关于多CPU、多核、超线程三者之间的差异,有兴趣的同学可以看“这里”。我个人感觉超线程不如多核与多CPU爽。

时间: 2024-10-31 19:26:07

C++多线程调试和测试的注意事项的相关文章

Java多线程调试

摘要 最有价值的调试工具是以线程为中心的.大部分 Java 错误都与线程交互有关.多线程调试让开发人员可以查看应用程序中运行的每个线程中的执行情况. SUN Laura Bennett 多线程调试基础 最有价值的调试工具是以线程为中心的.大部分 Java 错误都与线程交互有关.多线程调试让开发人员可以查看应用程序中运行的每个线程中的执行情况. 由于执行顺序的易变性,查找多线程应用程序中的错误比非线程化情况要困难得多.如果可以按相同的可预料顺序执行指令,那么调试这些应用程序就可以变得非常简单.当然

利用GDB进行多线程调试

一.多线程调试 多线程调试重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break file.c:100 thread all  在file.c文件第100行处为所有经过这里的线程设置断点. set scheduler-locking off|on|step,这个是问得最多的.在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试程序执行呢?通过这个命令就可以实现这

工程属性页,关于多线程调试MDd,MTD等等问题

问题描述 一个VC转成VC.net库文件,给C#工程调用现在问题有点奇怪,本来在工程属性--C/C++---代码生成页面下.运行库原先是设置的多线程调试(/MTd),编译工程,运行没有错误.现在设置,多线程调试(/MDd),编译工程,运行有错误.还原设置,多宣传调试(/MTd),编译工程,运行有错误.不明白原因.错误:托管调试助手"PInvokeStackImbalance"在......exe中检测到故障.其他信息:对PInvoke函数"Func"的调用导致堆栈不

(如图)请各位大神介绍下 visual studio 中的调试、测试和parasoft

问题描述 (如图)请各位大神介绍下 visual studio 中的调试.测试和parasoft 解决方案 不懂楼主想表达什么, 调试不就下断点, 开始调试, 设置调试的条件变量, 查看变量值, 查看callstack, 查看内存等么? parasoft 这个没用过呢.

多线程的那点儿事(之多线程调试)

 软件调试是我们软件开发过程中的重要一课.在前面,我们也讨论过程序调试,比如说这里.今天,我们还可以就软件调试多讲一些内容.比如说条件断点,数据断点,多线程断点等等. [cpp] view plaincopy #include <stdio.h>   int value = 0;      void test()   {       int total;       int index;          total = 0;       for(index = 0; index < 1

调试和测试Swing代码

Swing 是一个强大的 GUI 工具包:它可扩展.可配置且跨平台.不过 Swing 的灵活性既是它的主要优势也是它的重大弱点.Swing 可以不同的方式构建同一 UI.例如,您可以使用插页.空白边框或填充符在 GUI 组件之间置入间隔.鉴 于 Swing 选项太多,了解现有 GUI 如同编写新 GUI 一样令人畏惧,且将其视 觉外观与底层代码对应起来也并非易事.(试着在阅读几个使用 GridBagLayout 的代码行时想象一下 GUI.) 不管您是在维护未曾写过的 Swing GUI 还是集

大数据应用之HBase数据插入性能优化之多线程并行插入测试案例

一.引言: 上篇文章提起关于HBase插入性能优化设计到的五个参数,从参数配置的角度给大家提供了一个性能测试环境的实验代码.根据网友的反馈,基于单线程的模式实现的数据插入毕竟有限.通过个人实测,在我的虚拟机环境下,单线程插入数据的值约为4w/s.集群指标是:CPU双核1.83,虚拟机512M内存,集群部署单点模式.本文给出了基于多线程并发模式的,测试代码案例和实测结果,希望能给大家一些启示: 二.源程序: import org.apache.hadoop.conf.Configuration;

[Unity for android]Unity在安卓机上调试的测试环境搭建

一.工具准备 1.JDK--由于android是基于Java平台开发的,jdk是必须要安装的.下载地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin-b32-windows-i586-p-12_sep_2008.exe 2.Android SDK--这个就不多说了,要开发android程序必备的.可以去官网下载.下载地址:http://developer.android.com/sdk/

轻松把玩HttpClient之封装HttpClient工具类(四),单线程调用及多线程批量调用测试

       本文主要来分享一下该工具类的测试结果.工具类的整体源码不再单独分享,源码基本上都已经在文章中了.开始我们的测试.        单线程调用测试: public static void testOne() throws HttpProcessException{ System.out.println("--------简单方式调用(默认post)--------"); String url = "http://tool.oschina.net/"; //