- 论坛徽章:
- 0
|
回复 1# aple_smx
陈年旧帖被我翻起来,诸位勿怪。
昨天我与同事分析一个多线程应用的core,由于代码里无意中使用了localtime,计划改为localtime_r,顺便上网查资料,发现网上好多地方都在转载一篇文章,大谈什么localtime_r其实也是不安全的,该文出世之后弄得好多人都不敢再用 _r 类的函数了,起码我同事坚决认为换用localtime_r肯定解决不了问题。本贴楼主估计也是看了那个文章(或者别的地方转载的),认为localtime_r不安全,所以上来发问。
其实,localtime_r到底安全不安全,不能一概而论,特别是不能因为原文作者提到的glibc库对tzset()的实现有bug就把localtime_r一棍子打死。要知道c库随同操作系统有很多版本,不同厂家提供有不同的实现,glibc当年的这个版本的BUG,不能代表所有厂家的所有版本。
我用的是solaris10,SUN对自己实现的time类函数是这样说的(当然,别家可能不是这样):
The asctime(), ctime(), gmtime(), and localtime() functions are safe to use in multithread applications because they employ thread-specific data. However, their use is discouraged because standards do not require them to be thread-safe. The asctime_r() and gmtime_r() functions are MT-Safe. The ctime_r(), localtime_r(), and tzset() functions
are MT-Safe in multithread applications, as long as no user-defined function directly modifies one of the following variables: timezone, altzone, daylight, and tzname. These four variables are not MT-Safe to access. They are modified by the tzset() function in an MT-Safe manner. The mktime(), localtime_r(), and ctime_r() functions call tzset().
翻译过来就是说:
asctime(), ctime(), gmtime(), 以及localtime()这几个函数(的solaris版本)在多线程程序中被调用是安全的,因为它们的内部实现使用了“线程特定数据”技术。但还是不鼓励大家(在多线程程序中)使用它们,因为C标准并未要求这几个函数是多线程安全的(换句话说使用它们会带来移植性问题)。asctime_r() 和gmtime_r() 是多线程安全的。ctime_r()和localtime_r()以及tzset()函数也是多线程安全的,只要你不在自己的代码中直接修改timezone/altzone/daylight/tzname这四个(全局)变量就行。这4个变量不是多线程安全的(其实对任何全局变量的直接访问都不是多线程安全的)。 这4个变量由tzset()函数以一种多线程安全的方式进行修改(其实就是加锁)。而mktime()、localtime_r()和ctime_r()函数是使用tzset()这个函数(来使用4个全局变量的,所以是线程安全的)。
所以,起码solaris版本的localtime_r()是线程安全的,甚至连localtime()也是线程安全的(基于tsd技术,大家可以去看看“线程特定数据”的资料)。
为了进一步确认这个结论,防止solaris版的libc库也“说了不做”,导致tzset()函数内部其实并没有对4个全局变量进行加锁保护,我们翻出solaris的源代码来看看(solaris源码以opensolaris项目名义开源,贡献了绝大部分的源码,包括libc库)。源码我作为附件,这里说明如下:
time_gdata.c : 定义了传说中的那几个全局变量,以及用于保护它们的一把互斥锁。
localtime.c : 定义了所有那些time族函数,可以看到localtime_r()内确实使用了锁,而且localtime()函数内部用tsd申请空间后直接调用了localtime_r()函数。
time.zip
(20.63 KB, 下载次数: 241)
|
|