欢迎来到天天文库
浏览记录
ID:41037323
大小:90.00 KB
页数:7页
时间:2019-08-14
《UNIX_编程中错误输出的线程安全问题》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、UNIX编程中错误输出的线程安全问题2008年6月26日在多线程的UNIX应用程序中,系统调用出错时,错误输出有时可能不会像在单线程系统中那样正确的反应错误所在,因为需要考虑多线程情况下所使用的错误输出方式是否安全等问题。希望本文能对大家在多线程场景下选择错误报告的输出方式有所启发。系统调用失败原因分析在UNIX编程中,我们会经常使用系统调用来完成期望的功能;而与此同时,我们也需要付出大段的代码来检测、输出错误和其他意外情况。以下是系统调用失败的可能原因:系统可能出现资源短缺或者程序使用的资源可能超过系统为单个程序规
2、定的上限。常见的情况有:程序可能尝试分配大量内存,或者同时打开很多文件等。程序执行操作时,可能会由于权限不足而被系统阻止。例如,程序可能会试图写一个只读的文件,或者企图访问其他进程的内存空间。传入系统调用的参数可能无效,原因可能是用户提供无效输入或者程序本身的bug。例如,程序可能会传入一个无效的内存地址或者无效的文件描述符。系统调用还有可能因为程序之外的原因出错。系统调用访问硬件的时候经常会有这种情况发生。设备可能会出现异常错误或者不支持特定的操作,或者可能会出现磁盘没有插入驱动器中的情况出现。系统调用有的时候会被
3、外部事件(如信号等)中断。这可能不代表真正的调用失败,但是如果有必要,程序应当重新尝试执行系统调用。回页首库函数的线程安全Glibc为上述系统调用失败场景提供了丰富的库函数来处理错误输出。但是任何事物都存在双刃剑,这些错误输出库函数在为我们带来便利的同时,也给我们带来了一定的安全隐患——线程安全问题。线程安全是为了避免数据竞争或者数据设置的正确性依赖于多个线程修改数据的顺序。假设你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也
4、和预期的是一样的,就是线程安全的。对于函数来说,在多线程或有异常控制流的情况下,当某个函数运行到中途时,控制流(也就是当前指令序列)就有可能被打断而去执行另一个函数。而这个函数很有可能是它本身。如果在这种情况下不会出现问题,比如说数据或状态不会被破坏,行为确定。那么这个函数就被称做"可重入"的。在多线程编程中,有两种方法使库函数可以保证其安全。一个是简单的将合适的代码使用互斥锁包起来,这样可以保证同时只有一个线程执行这一段例程。虽然这种方法大部分情况下都能奏效,但是它的性能却非常糟糕。而且对于诸如strtok函数,该
5、方法就完全不能工作了,因此很多UNIX系统都存在_r的接口函数。另一个更好的办法是确保库函数可以同时在多个线程情况下安全的执行。这里指的不仅仅是带有后缀_r的可重入对等函数;毕竟可重入和线程安全(Thread-Safe)是两个不同的概念:可重入函数一定是线程安全的;线程安全的函数可能是重入的,也可能是不重入的;线程不安全的函数一定是不可重入的。所以诸如malloc,free等函数也在此列,属于线程安全的库函数。当然,如果你在单线程应用程序中使用线程安全函数会在一定程度上降低性能,所以尽量避免在单线程应用程序中使用它们
6、。回页首程序清单这里先快速浏览一下本文中所要使用的样例程序代码,方便后面的比较说明。清单1尝试打开一个文件,如果打开文件失败,将打印一串错误信息并退出程序。注意:调用fopen函数如果操作成功的话返回一个打开文件的描述符,当操作失败的时候返回NULL。清单1系统调用的错误输出//filename:test.c#include#include#include#includeconstchar*INFILE="~/text";intmain(){
7、FILE*fd=0;charbuf[64];memset(buf,0,sizeof(buf));printf("Trytoopeninputfile%s...",INFILE);fd=fopen(INFILE,"r");if(fd==NULL){#ifdefPERRORperror("(PERROR)Erroropeninginfile");#endif#ifdefSTRERRORprintf("(STRERROR)Erroropeninginfile:%s",strerror(errno));#endif#
8、ifdefPERROR_STRERRORperror("(PERROR)Erroropeninginfile");printf("(STRERROR)Erroropeninginfile:%s",strerror(errno));#endif#ifdefSTRERROR_Rstrerror_r(errno,buf,sizeof(buf));
此文档下载收益归作者所有