localtime线程不安全,localtime_r时区问题
#include /* The C Standard says that localtime and gmtime return the same pointer. */
struct tm _tmbuf;/* Return the `struct tm' representation of *T in local time,using *TP to store the result. */
struct tm *
__localtime_r (t, tp)const time_t *t;struct tm *tp;
{return __tz_convert (t, 1, tp);
}
weak_alias (__localtime_r, localtime_r)/* Return the `struct tm' representation of *T in local time. */
struct tm *
localtime (t)const time_t *t;
{return __tz_convert (t, 1, &_tmbuf);
}
libc_hidden_def (localtime)
都是调用__tz_convert(),区别在于:
The four functions asctime(), ctime(), gmtime() and localtime() return a pointer to static data and hence are not thread-safe.
static struct tm *
localtime_r (const time_t *t, struct tm *tp)
{ struct tm *l = localtime (t); if (! l) return 0; *tp = *l; return tp; }
According to POSIX.1-2004, localtime() is required to behave as though tzset(3) was called, while localtime_r() does not have this requirement. For portable code tzset(3) should be called before localtime_r().
翻译:localtime像调用过了tzset一样。localtime_r没有,所以之前需要主动调用tzset,否则时区更改后localtime_r并不会生效。
tzset的实现就是调用tzset_internal,而__tz_convert中也会调用。
struct tm *
__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
{ ...... __libc_lock_lock (tzset_lock); //加锁 tzset_internal (tp == &_tmbuf, 0);...... //时间转换逻辑 __libc_lock_unlock (tzset_lock); //释放锁 ...... return tp;
}
void
__tzset (void)
{__libc_lock_lock (tzset_lock);tzset_internal (1, 1);if (!__use_tzfile){/* Set `tzname'. */__tzname[0] = (char *) tz_rules[0].name;__tzname[1] = (char *) tz_rules[1].name;}__libc_lock_unlock (tzset_lock);
}
weak_alias (__tzset, tzset)
struct tm *
my_localtime_r (t, tp)const time_t *t;struct tm *tp;
{tzset();return localtime_r(t, tp);
}