localtime和mktime是用来在时间分量和时间秒数之间进行转换的标准c函数。 在glibc的文档描述中,localtime的实现是使用了一个内部静态缓存来保存结果,所以这是一个不可用于多线程环境的api。glibc提供了一个线程安全版本localtime_r。mktime不存在这个问题。 所以,按照glibc的文档,在多线程环境下可以安全的使用localtime_r和mktime,实际情况并非如此。 mktime和localtime_r在实现上都考虑了时区的转换,而时区的计算要使用全局变量tzname/timezone/daylight。这本质上就是线程不安全的。 参考glibc-2.3.2的源代码(下面的源代码位置都是相对于源码根目录的) --------- time/localtime.c 和 time/tzset.c localtime_r中调用了tzset_internal来设置时区,入口参数为always=0,所以理论上只要第一次初次化过了,就不需初始化了。参考下面的代码。
/* Interpret the TZ envariable. */ if (is_initialized && !always) 但是mktime不是这样的, ---- (time/mktime.c) ------- /* Convert *TP to a time_t value. */ return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset); 由于_LIBC被定义,所以tzset将每次都被调用,而tzset的代码是这样的 ---- (time/tzset.c) ------- void tzset_internal (1); if (!__use_tzfile) __libc_lock_unlock (tzset_lock); tzset_internal将每次都被调用,时区信息将每次都被重写。 需要说明的是,前面的宏__libc_lock_lock在sysdeps/generic/bits/libc-lock.h中定义为: 所以,可以看到,glibc的上述代码实现中,有两个问题: 所以mktime和localtime_r不适合于多线程应用。
|
|
来自: 昵称17328427 > 《Linux》