What is _GLIBCXX_USE_NANOSLEEP all about?

2019-01-18 08:48发布

问题:

A preprocessor macro called _GLIBCXX_USE_NANOSLEEP appears in two standard header files:

  • c++/4.7.1/x86_64-unknown-linux-gnu/bits/c++config.h
  • c++/4.7.1/thread

In a default build of GCC 4.7.1 (Linux, 64-bit) the only thing c++config.h includes is this comment:

/* Defined if nanosleep is available. */
/* #undef _GLIBCXX_USE_NANOSLEEP */

Whereas in thread, the definition of std::this_thread::sleep_for() and std::this_thread::sleep_until() depend on the macro to be defined. If it isn't defined, both functions – although required by the C++ Standard – won't be defined either.

On my system (glibc 2.15), the macro is not defined, although the nanosleep() function (declared in ctime) exists and is operational.

I'd like to know what this is all about and how to deal with it. Specifically:

  • Is there a configuration option that should be used when building GCC to activate this macro by default, as suggested by this post? (I couldn't find any in the online documentation of the build process.)
  • Is there really a relation between the nanosleep() function and the macro? The declaration of nanosleep() in ctime/time.h does not seem to depend on, or define, the macro.
  • Is there any specific risk involved in defining the macro in my own header files, or as a -D option on the command line (as suggested in this related question)? What if I do this on a system where nanosleep() is not available, and how can I actually find out?

Update From GCC 4.8 onwards, support for std::this_thread::sleep_for() and the like is automatically included in libstdc++. No configuration flag is required any more. From the GCC 4.8 change log:

this_thread::sleep_for(), this_thread::sleep_until() and this_thread::yield() are defined without requiring the configure option --enable-libstdcxx-time;

But note the further details on this for GCC 4.8 and 4.9 given in Jonathan's answer.

回答1:

When libstdc++ is built its configure script tests your system to see what features are supported, and based on the results it defines (or undefines) various macros in c++config.h

In your case configure determined that the POSIX nanosleep() function is not available and the macro is not defined. However, as you say, nanosleep() is available on your system. The reason it's not enabled by configure is that the checks for it don't even run unless you use the --enable-libstdcxx-time option (documented in the Configuration chapter of the libstdc++ manual, not the GCC configure docs)

  • Is there a configuration option that should be used when building GCC to activate this macro by default, as suggested by this post? (I couldn't find any in the online documentation of the build process.)

Yes, --enable-libstdcxx-time

  • Is there really a relation between the nanosleep() function and the macro? The declaration of nanosleep() in ctime/time.h does not seem to depend on, or define, the macro.

The declaration of glibc's function doesn't depend on libstdc++'s macro, no. But the macro tells libstdc++ whether to use the function or not.

  • Is there any specific risk involved in defining the macro in my own header files, or as a -D option on the command line (as suggested in this related question)? What if I do this on a system where nanosleep() is not available, and how can I actually find out?

It's naughty and is unsupported, but will work. The macro is an internal implementation detail that should be set by configure and not by users and changing the definition of the implementation's internal macros can break things. But in this case it won't because the only code that depends on it is in a header, no library code in libstdc++.so is affected.

But it would be better to reinstall GCC and use the --enable-libstdcxx-time option, or if that's not possible edit your c++config.h to define the macro to true.

If you define it on a different system where nanosleep() isn't available you'll get a compilation error when you #include <thread>.

I have some ideas for improving that configuration, so nanosleep() and sched_yield() will be checked for by default, but I haven't had time to work on them yet.

Update: I've committed some changes so that building GCC 4.8 without --enable-libstdcxx-time will still define std::this_thread::yield() (as a no-op) and will implement std::this_thread::sleep_for() and std::this_thread::sleep_until() using the lower resolution ::sleep() and ::usleep() functions instead of ::nanosleep(). It's still better to define --enable-libstdcxx-time though.

Another update: GCC 4.9.0 is out and now defaults to automatically enabling nanosleep and sched_yield on platforms that are known to support them. There is no longer any need to use --enable-libstdcxx-time.