9

The man page of mktime didn't mention thread safety of mktime, but it did mention this which make it look like thread unsafe:

Calling mktime() also sets the external variable tzname with information about the current time zone.

I know on Linux mktime calls tzset to set tzname, which is a char*[]:

extern char *tzname[2];

and tzset will read environment variable TZ and file /etc/localtime. So unless mktime uses a mutex to protect all these operations, I can't see how it can be thread safe.

swang
  • 5,157
  • 5
  • 33
  • 55
  • possible duplicate of [C time function multiple thread](http://stackoverflow.com/questions/18348383/c-time-function-multiple-thread) – Shafik Yaghmour Aug 21 '13 at 12:05
  • @ShafikYaghmour The previous question and its answers concentrate on `asctime`, `ctime`, `gmtime` and `localtime` which return pointers to static data and are therefore thread-unsafe by design. This question is specifically about `mktime` whose interface is not thread-unsafe, but the side effect additionally mandated by POSIX could be. Therefore this is not a duplicate of the previous question. – user4815162342 Aug 21 '13 at 13:28
  • that's right, I think the first two lines added are a bit misleading, the previous question didn't answer anything regarding mktime. – swang Aug 21 '13 at 14:59
  • @user4815162342 If the C standard and POSIX conflict then the [C standard wins](http://stackoverflow.com/a/9377007/1708801). The C standard indicates `mktime` is thread safe as my answer to the question I indicated as a dup explains at the end. – Shafik Yaghmour Aug 23 '13 at 14:45
  • @ShafikYaghmour C99 doesn't indicate that `mktime` is thread-safe because threads are not part of C99 - what it does state is that subsequent calls won't overrun the result of previous ones (or, more precisely, it fails to state that such a thing could happen). POSIX `mktime` includes additional functionality which does not conflict with the one in C99, so the "in case of conflict, C wins" rule doesn't apply. Again, it is quite reasonable to ask whether the functionality added by POSIX is thread-safe. – user4815162342 Aug 23 '13 at 15:03

1 Answers1

11

It's true that mktime has a side effect, but the side effect should be harmless in most programs.

According to POSIX, the side effect will be as if tzset has been called, which in turn merely copies the timezone information from the TZ environment variable to the tzname array of C strings. If your application doesn't change TZ, you will have no problem with calling mktime() concurrently.

In addition to this, GNU libc's tzset does use a mutex to protect the integrity of tzname. This is a quality-of-implementation addition not guaranteed by the standard.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • well, but it looks TZ can be changed by many other time functions, eg. strftime, or by calling tzset directly. Also TZ usually points to a file which is symlinked from /etc/localtime, which can be changed at any time as well? – swang Aug 21 '13 at 10:51
  • Sorry didn't see your edit, this makes more sense, the whole tzset call is protected by a mutex, so any time function using timezone information will be synchronized at the mutex, including strptime and strftime. This does guarantees thread safety, but sounds very inefficient to me. – swang Aug 21 '13 at 10:59
  • @swang `tzset` has a [fast path](http://sourceware.org/git/?p=glibc.git;a=blame;f=time/tzset.c;hb=26b4d7667169f8db26fd8194b3c498ec58e50f90#l173) that bails out if the value of the `TZ` environment variable hasn't changed, changes to `/etc/localtime` notwithstanding. Because of that its efficiency should be reasonable. – user4815162342 Aug 21 '13 at 13:25
  • 1
    you are right, but the inefficiency still exists because of the mutex, if I have multiple threads calling different time functions I'm introducing a implicit synchronizing point. I did strace on my application and indeed see __lll_lock_wait_private() from threads using strftime, presumably because one thread calling mktime is doing tzset_internal(). – swang Aug 21 '13 at 14:56
  • @swang In my experience the libc time functions are not written for high efficiency, so my intuition would be that a mutex (especially when uncontested, in which case it stays in user space) would not introduce a measurable slowdown. But I have zero data to support that hunch, and I haven't studied the implementation of glibc private locks. – user4815162342 Aug 21 '13 at 15:07