检查Pthreads函数的返回值

来源:互联网 发布:淘宝哪个二手手机 编辑:程序博客网 时间:2024/05/17 20:32

一定要检查函数的返回值

 

     《C/C++软件测试规范》上有很重要的一条就是要检查所有返回值不为空的函数的返回值来判断库函数或者系统调用的执行是否成功。如果读一些经典开源代码,你会发现几乎每一个函数的调用都会被放置在一个if语句中来检查被调用函数的执行情况。经常会看到超市收银台的电脑上或者学校的自助充值终端甚至是火车站购票的大屏幕上会弹出Windows的对话框显示“0xXXXXXXXXX位置内存不能为读”之类的错误。这在很多情况下都是没有判断函数返回值或者是没有添加异常处理而埋下的炸弹。

     当然在每个函数上都添加一个返回值检查的代码不是一件很困难的事情,但是至少有两个心理因素导致编程者不愿意实现:

     (1)需要重复的添加很多类似的代码。

     (2)潜在的降低软件的运行速度。

      第一个问题,可以用宏来解决。第二个问题上,表面上看貌似会降低速度,但事实上,一个函数所导致的需要执行的指令一般也是上万条,而一个if语句也只是几条指令而已;添加这些代码,可能会增加编译时间,但运行时间几乎不会有影响。

     检查返回值能提升软件的鲁棒性,这是因为软件的鲁棒性很多时候是由编程者自己思维的严谨程度决定的。另外,还有一个巨大的优点就是大大的减少了调试时间。如果你一次写了很多个模块才调试,没有添加这些检查语句会导致耗费掉数个小时才能找到一个bug。如果你确实用C语言编写过运行在数百台机器上的分布式程序的话,你会发现不检查函数返回值简直就是噩梦,而且醒来之后还在噩梦中(dream within dream) :D。

 

Unix、C、Pthreads中错误检查机制

     传统上,C语言的库函数和Unix的系统调用在执行成功的时候会返回0或者返回一个接口规定的值。失败的时候,函数会返回-1同时设置errno. errno是一个可读可写的整型变量,一般要将其翻译为可识别的字符串提示,一般常用的函数为perror或者strerror。

     这种机制至少有这么几个问题:

     (1)创建一个函数既能设置errno又能返回-1比较困难。

     (2)多线程环境下,可能会有多个线程同时读写errno.

     所以Pthreads库中的函数执行失败时,直接返回错误码,而不是设置errno.同时在支持Pthreads库的Unix系统上,errno是一个线程安全的类型。即:每个线程都有属于自己的errno和其他线程的errno无关,这样就不会出现竞争了。但是,并不推荐使用线程相关的errno,因为其开销较大,推荐使用利用返回值或者是传出参数来说明函数的执行情况,这样速度就快多了。

 

支持Unix、C、Phtreads的错误检查宏

     使用宏的好处:

     (1)减少代码冗余

     (2)执行速度快

     (3)在编译时表达语义,有很多运行时不能实现和代码源文件相关的效果。比如显示出错的行号,出错的函数名称,出错的文件名称等等。(据说宏的表达能力和图灵机等价…)

     (4)提高可读性

     下面为判断出Pthreads接口函数出错后,做的错误处理的宏

         #define err_abort(code,text) do {   \

                                    fprintf(stderr,”%s at \”%s\”:%d: %s\n”, \

                                         text,__FILE__,__LINE__,strerror(code); \

                                    abort(); \

                                    )while(0)

     下面为判断出Linux、C接口函数出错后,做的错误处理的宏

         define error_abort(text) do { \

                                fprintf(stderr,”%s at \”%s\”:%d: %s\n” \

                                text,__FILE__,__LINE__,strerror(errno); \

                                abort(); \

                                )while(0)