Will getting the current date/time be thread-safe

2020-08-12 04:38发布

问题:

Short Question

Up to and including C++17, C++ provides no thread-safe way to get the current time or date. Will this be fixed in C++20?

Long Question

The only portable way to get the current time and date is by using the std::gmtime or std::localtime functions. Remnants from the early days of C, these functions convert a given time since an implementation-defined epoch into calender time (for example, 1515153600 into Fri, 05 Jan 2018 12:00:00 GMT). The only downside, however, is that those functions return a pointer to an internal static variable and aren't threadsafe. What's even worse is that this static variable may be shared by all related functions such as std::gmtime, std::localtime, and std::ctime and may be overwritten on each invocation of any of those functions. So if you're using threads and want to regularly check the time you risk data races and undefined behavior.

Clearly the current standard is broken in this regard. Is there any effort by the C++ standard committee to fix this situation and how likely is this going to be included in C++20?

回答1:

Howard Hinnant's date library is what's coming for C++20. It was proposed via p0355r4 and approved for C++20 in Nov. 2017. Is it thread safe? Unfortunately, neither the documentation nor proposal seem to be clear on this. However, certain functions like get_tzdb_list are explicitly said to have "Thread Safety". Your best option is to ask Hinnant himself in the gitter chat. However, discussion in Why is there no C++11 threadsafe alternative to std::localtime and std::gmtime? seems to suggest that it is thread-safe (even though it's never explicitly said). As Nicol Bolas points out you can just wrap it behind a mutex.

If it doesn't you can again get data races and hence undefined behavior. If you're coding on large projects where coding work is divided into teams, you have to continously remind everyone that they should not (!) use the functions provided by the C++ standard, but use your own wrapper instead (or risk undefined behavior).

At a shallow level, this is what code reviews are for. Facebook has this problem for junior developers where they keep making the same bugs over and over. If your team has "curiously recurring bugs", you need to address it somehow (like adding checks to linter: Clang comes to mind).

At a much more direct level, Google is the epitome of this. The problem they were having was using the old COW implementation of string and switching over to SSO-based string. However, because they relied on third party libraries that used COW-based string, they needed to support both in their codebase. Telling developers to use the Google wrapper was a futile effort. The solution the developer came up with was using a hack with inline namespaces. A bit extreme, but if you are dealing with a similarly large codebase, it could do the trick.