考虑以下简单的C程序,
#include <errno.h>
int
main(int argc, char* argv[]) {
return errno;
}
Run Code Online (Sandbox Code Playgroud)
在Solaris上编译时,此代码的行为取决于是否存在-D_REENTRANT.
solaris$ cc -E test.c | grep return
return errno;
solaris$ cc -D_REENTRANT -E test.c | grep return
return ( * ( ___errno ( ) ) );
Run Code Online (Sandbox Code Playgroud)
后一版本是线程安全的.如果我们在Linux上编译相同的代码,我们将获得与之相同的行为-D_REENTRANT
linux$ gcc -E test.c | grep return
return (*__errno_location ());
linux$ gcc -D_REENTRANT -E test.c | grep return
return (*__errno_location ());
Run Code Online (Sandbox Code Playgroud)
Solaris的cc有选项-mt,这意味着-D_REENTRANT,一样gcc的-pthread.但是,对于库,指定这些多线程选项似乎很差,因为它会对线程运行时注入不必要的依赖.但是,如果库需要是线程安全的(包括errno),那么在库的编译时和派生代码的编译时都需要线程安全的语义.在Linux上,这很容易,因为errno总是线程本地的,但是在其他系统上并不能保证这一点.
这导致了一个问题:如何正确编译线程安全的库并使用头文件进行分发?一个选项是#define _REENTRANT在主标题中,但如果#include …