为什么 gmtime_r 调用 __tz_convert 获取全局锁?

Why does gmtime_r call __tz_convert which grabs a global lock?

我惊讶地发现 gmtime_r 真的在调用 tz-anything。我认为存在 localtime 与 gmtime 的原因是前者进行 tz 转换而后者不需要。看起来 gmtime 调用 __tz_convert,然后继续并获取 tz 上的全局锁(它甚至不需要......对吧?) 我在这里错过了什么吗? 如何在多线程应用程序中高效转换 epoch -> struct tm?

(gdb) where
#0  0x00007fffee255eec in __lll_lock_wait_private () from /lib64/libc.so.6
#1  0x00007fffee2007bc in _L_lock_2546 () from /lib64/libc.so.6
#2  0x00007fffee2005f7 in __tz_convert () from /lib64/libc.so.6
#3  0x000000000041c63f in DateTimeEx (dt=..., this=0x7fffca551900) at /var/lib/jenkins/workspace/hfalgo_src_hotfix_1.69.1-T6J4HNFQDMYVEKV4MEGVD6UCCPG7KHWQDOSVYBUDROFXZA6YINSA/hfalgo_src/./core/Time.h:81

glibc 可以处理包含闰秒信息的时区数据库文件,gmtimegmtime_r 将这些闰秒考虑在内。 (例如,Debian tzdata 包在 /usr/share/zoneinfo/right 目录中提供了这样的时区文件。)这就是为什么 glibc 实现读取时区数据库并执行一些与此相关的锁定。

我不知道有人在实际使用闰秒功能。 POSIX 目前要求自纪元以来的计数不考虑任何闰秒,因此使用具有闰秒的数据文件会导致函数的不一致行为,例如 gmtime.

但是,我希望某些非便携式软件依赖于调用 gmtimegmtime_r 执行隐式 tzset 调用这一事实,从而初始化 tzname 和其他全局变量。这是从当前实现中消除锁定的更大障碍。 (有人甚至为此悬赏,但 100 美元与修复此问题所需的努力完全不成比例。)

如果你今天需要避免锁,你需要查找gmtime算法(Calendrical Calculations是这些问题的有趣参考)并实现它你自己。