Mktime and Localtime

zhaozj2021-02-16  76

LocalTime and MKTIME are standard C functions used to convert between time components and time seconds.

In the Document Description of Glibc, the implementation of localtime uses an internal static cache to save the result, so this is an API that is not available for multi-threaded environments. GLIBC provides a thread security version localtime_r. There is no such problem in Mktime.

So, according to GLIBC's documentation, use LocalTime_R and MKTIME safely in multithreaded environments, this is not the case.

MkTime and LocalTime_R take into account the conversion of time zones, while the time zone is calculated using global variables Tzname / TimeZone / Daylight. This is essentially the thread is not safe.

Refer to the source code of GLIBC-2.3.2 (the following source code location is relative to the source root directory)

--------- Time / localtime.c and time / tzset.c

TZSET_INTERNAL is called in localtime_r to set the time zone, the entrance parameter is always = 0, so as long as the first initialization is over, it will not need to initialize. Refer to the following code. However, since the static variable is_initialize is introduced, this implementation code is problematic in a multi-threaded environment. It is impossible to guarantee the correctness of concurrent execution environment.

---- (TIME / TZSET.C) -------

. / * Interpret the TZ envariable * / static voidinternal_functiontzset_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; ...........}

But mktime is not like this,

---- (Time / mktime.c) -------

/ * Convert * TP to a time_t value. * / Time_tmktime (TP) StructTM * 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);

Since _LIBC is defined, Tzset will be called each time, and the tzset code is like this.

---- (TIME / TZSET.C) -------

Void__tzset (void) {__libc_lock_lock (tzset_lock);

TZSET_INTERNAL (1);

IF (! __ ue) {/ * set `tzname '. * / __tzname [0] = (char *) TZ_Rules [0] .Name; __tzname [1] = (char *) TZ_Rules [1] .name;} __ libc_lock_unlock TZSET_LOCK);

TZSET_INTERNAL will be called each time, and the time zone information will be rewritten each time.

It should be noted that the front macro __libc_lock_lock is defined in sysdeps / generic / bits / libc-lock.h as: #define __libc_lock_lock (name) is an empty operation, so it does not function as a synchronous thread.

Therefore, it can be seen that there are two problems in the above-described code implementation of GLIBC: 1. STATIC variables used in tzset_internal (this we can define a useless global variable in the program, before the thread starts, it In initialization, Mktime is called to overcome) 2, Mktime has to rewrite the global variable Tzname / Timezone / Daylight every time (this problem, there is no way to solve it)

So MKTIME and LOCALTIME_R are not suitable for multi-threaded applications.

Solutions are two: 1, to achieve MKTIME and LOCALTIME_R, but the calculation of the time zone is troubles, of course, can also use fixed time zones, such as the Beijing time zone, so it is much simpler. 2, use PThread's Mutex to lock Mktime and LocalTime_r, but this should be used with PTHREAD libraries, which is not good enough.

转载请注明原文地址:https://www.9cbs.com/read-16857.html

New Post(0)