localtime线程不安全与localtime_r时区问题
创始人
2025-05-29 20:39:14

文章目录

      • 1. 代码实现
      • 2. 线程安全问题
        • 2.1 原因
        • 2.2 解决线程不安全
      • 3. 时区问题
        • 3.1 怎么理解“localtime像调用过了tzset一样”
        • 3.2 解决localtime_r时区问题
      • 4.死锁问题

localtime线程不安全,localtime_r时区问题

1. 代码实现

#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(),区别在于:

  • localtime传参及返回值为库中全局变量_tmbuf
  • localtime_r参数及返回值都为上层的传参

2. 线程安全问题

2.1 原因

The four functions asctime(), ctime(), gmtime() and localtime() return a pointer to static data and hence are not thread-safe.

  • localtime调用__tz_convert()第三个参数为全局变量_tmbuf,并且其返回值也是_tmbuf的指针。返回指针所指向的全局变量的值可能被其他线程调用localtime给修改掉。所以localtime是线程不安全的。
  • localtime_r改用调用者传入的变量指针为参数,每个线程都会传入自己的变量指针,所以是线程安全的。

2.2 解决线程不安全

  • 网上有看到一种localtime_r的实现,直接调用localtime,说改成了线程安全的实现了,其实依旧是线程不安全的。也许需要再加一层锁,不然问题一样。
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; }
  • 最好的方法可能是将localtime替换为调用glibc中的localtime_r,但localtime_r有时区问题

3. 时区问题

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并不会生效。

3.1 怎么理解“localtime像调用过了tzset一样”

tzset的实现就是调用tzset_internal,而__tz_convert中也会调用。

  • localtime调用时(tp == &_tmbuf)成立为1,所以和tzset效果差不多,会去根据当前时区更新数据;
  • 而localtime_r则为0,只会在初始化的时候更新一次时区数据。因此在时区更改之后,需要在调用localtime_r之前主动调用tzset,否则获取的时间就不会随时区而变化。
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)

3.2 解决localtime_r时区问题

  • 封装新接口。需要将工程中的localtime_r全部替换。
struct tm *
my_localtime_r (t, tp)const time_t *t;struct tm *tp;
{tzset();return localtime_r(t, tp);
}
  • 重构localtime_r

4.死锁问题

相关内容

热门资讯

海南自贸港正式启动封关!29只... 本文来源:时代周报 作者:张汀雯 图片来源:图虫创意12月18日,一艘装载17.9万吨石化原辅料的...
每日看盘|AI资产褪色,动量资... 周四A股市场出现了震荡中有所分化的态势。其中,以CPO为代表的AI硬件主线回落,驱动着创业板指、科创...
我区召开“强服务 惠民生”新闻... 12月17日,我区召开“强服务 惠民生”新闻发布会,介绍今年我区民生工作开展情况,区人社局有关负责人...
“中国人能造全球最便宜商品,却... 文 | 清和 智本社社长香港中文大学(深圳)教授陶然在接受凤凰卫视采访时提出一个问题:“中国人能造...
摩尔线程IPO后75亿额度理财... 摩尔线程需要先做好平台。摩尔线程75亿理财到底冤不冤如果说2024年市场追逐的是“大模型概念”,20...