mktime和localtime_r能在多线程环境下使用么?

原创 2004年07月12日 16:18:00

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,所以理论上只要第一次初次化过了,就不需初始化了。参考下面的代码。
但是由于引入了静态变量is_initialized,在多线程环境下,这种实现代码是有问题的。无法保证并发执行环境下的正确性。


---- (time/tzset.c) -------

/* Interpret the TZ envariable.  */
static void
internal_function
tzset_internal (always)
     int always;
{
  static int is_initialized;
  register const char *tz;
  register size_t l;
  char *tzbuf;
  unsigned short int hh, mm, ss;
  unsigned short int whichrule;

  if (is_initialized && !always)
    return;
  is_initialized = 1;
...........
}

但是mktime不是这样的,

---- (time/mktime.c) -------

/* Convert *TP to a time_t value.  */
time_t
mktime (tp)
     struct tm *tp;
{
#ifdef _LIBC
  /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
     time zone names contained in the external variable `tzname' shall
     be set as if the tzset() function had been called.  */
  __tzset ();
#endif

  return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset);
}

由于_LIBC被定义,所以tzset将每次都被调用,而tzset的代码是这样的

---- (time/tzset.c) -------

void
__tzset (void)
{
  __libc_lock_lock (tzset_lock);

  tzset_internal (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);
}

tzset_internal将每次都被调用,时区信息将每次都被重写。

需要说明的是,前面的宏__libc_lock_lock在sysdeps/generic/bits/libc-lock.h中定义为:
#define __libc_lock_lock(NAME)
是个空操作,所以它不能起到同步线程的作用。

所以,可以看到,glibc的上述代码实现中,有两个问题:
1、tzset_internal 中使用的static变量is_initialized
(这个我们可以通过在程序中定义一个无用的全局变量,在线程开始工作前,它的初始化中调用一次mktime来克服)
2、mktime每次都要重写全局变量tzname/timezone/daylight
(这个问题,基本上,就没办法解决了)

所以mktime和localtime_r不适合于多线程应用。


解决方案有二:
1、自己实现mktime和localtime_r,但是这样时区的计算是麻烦的,当然也可以不使用时区信息,或者使用固定时区,比如北京时区,这样就简单多了。
2、用pthread的mutex来给mktime和localtime_r加锁,但是这样要使用pthread库,移植性不够好。

测试mktime和localtime_r性能及优化方法

// 编译方法:g++ -g -o x x.cpp或g++ -O2 -o x x.cpp,两种编译方式性能基本相同。 // // 结论: // 1) 环境变量TZ和isdst均不影响localtime...
  • Aquester
  • Aquester
  • 2017年01月22日 16:23
  • 713

mktime和localtime_r时间转换问题

2012-08-26 wcdj 由UNIX时间戳转换为系统时间 date -d'1970-01-01 UTC 2147483647 seconds' +"%Y-%m-%d %T %z"...
  • delphiwcdj
  • delphiwcdj
  • 2012年08月26日 10:50
  • 6378

多线程使用时间函数

linux的时间函数有其特别需要注意的使用方法,在工程项目中,这点很容易忽视,本文就时间函数在多线程中的使用作一个小结。 首先看一个函数,取下一天的功能函数,该函数使用了时间函数localtim...
  • j6915819
  • j6915819
  • 2015年10月16日 10:53
  • 1377

多线程中使用mktime和setenv函数

在编写ATS插件的过程中,发现使用mktime会偶尔出现段错误, 经过网上调研,发现mktime等函数不是线程安全的, 于是编写下面的代码进行测试. 注意加锁和不加锁区别很大, 在mktime中使用多...
  • tao_627
  • tao_627
  • 2015年06月27日 10:54
  • 839

strftime, localtime_r(替代localtime), gettimeofday(替代ftime)

一、        size_t strftime(char *s, size_t max, const char *format,                            const ...
  • an_zhenwei
  • an_zhenwei
  • 2013年01月29日 11:13
  • 3932

mktime和localtime_r能在多线程环境下使用么?

localtime和mktime是用来在时间分量和时间秒数之间进行转换的标准c函数。 在glibc的文档描述中,localtime的实现是使用了一个内部静态缓存来保存结果,所以这是一个不可用于多线程环...
  • clkrst
  • clkrst
  • 2004年07月12日 16:18
  • 8934

C/C++获取时间方法:gettimeofday()

获取时间
  • u013652219
  • u013652219
  • 2015年04月18日 10:18
  • 9108

多线程情况下慎用localtime_r

最近有个需求,需要提升日志模块的性能。当前日志模块每秒钟处理的日志数量大概在55w左右,于是进行优化,在日志的IO线程中将sprintf剥离,提前将时间、日志等级等格式化处理。 于是这样就产生了一个问...
  • sryan
  • sryan
  • 2016年04月26日 11:56
  • 3190

彻头彻尾理解单例模式及其在多线程环境中的应用

摘要:      本文首先概述了单例模式产生动机,揭示了单例模式的本质和应用场景。紧接着,我们给出了单例模式在单线程环境下的两种经典实现:饿汉式 和 懒汉式,但是饿汉式是线程安全的,而懒汉式是非线...
  • fuzhongmin05
  • fuzhongmin05
  • 2017年04月30日 11:43
  • 634

C语言linux环境下使用gettimeofday函数得到程序运行时间

编写的一个打字游戏中需要计算程序的运行时间,通过网上查阅资料发现大多数都是说通过clock()函数来获取时间,之后做差从而的到程序的运行时间。但是在linux中测试以后发现结果是0,并不能得到程序的运...
  • lvlvituotuo
  • lvlvituotuo
  • 2016年10月18日 23:13
  • 1657
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:mktime和localtime_r能在多线程环境下使用么?
举报原因:
原因补充:

(最多只允许输入30个字)