Consider the following trivial C program,
考虑以下简单的C程序,
#include <errno.h>
int
main(int argc, char* argv[]) {
return errno;
}
When compiled on Solaris, the behavior of this code is dependent on the presence of -D_REENTRANT
.
在Solaris上编译时,此代码的行为取决于-D_REENTRANT的存在。
solaris$ cc -E test.c | grep return
return errno;
solaris$ cc -D_REENTRANT -E test.c | grep return
return ( * ( ___errno ( ) ) );
with the latter version being thread-safe. If we compile the same code on Linux, we get the same behavior independent of -D_REENTRANT
后一版本是线程安全的。如果我们在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 ());
Solaris' cc
has the option -mt
, which implies -D_REENTRANT
, as does gcc
's -pthread
. However, for a library, specifying these multi-threaded options seems poor, as it injects an unnecessary dependency on the threading runtime. However, if the library needs to be thread-safe (including errno), then the thread-safe semantics are needed at both compile time of the library and of the deriving code. On Linux, this is easy, because errno is always thread-local, but that's not guaranteed on other systems as just demonstrated.
Solaris'cc有选项-mt,它意味着-D_REENTRANT,和gcc的-pthread一样。但是,对于库,指定这些多线程选项似乎很差,因为它会对线程运行时注入不必要的依赖。但是,如果库需要是线程安全的(包括errno),那么在库的编译时和派生代码的编译时都需要线程安全的语义。在Linux上,这很容易,因为errno总是线程本地的,但是在其他系统上并不能保证这一点。
That results in the question: how is a thread-safe library properly compiled and distributed with headers? One option would be to #define _REENTRANT
in the main header, but this would cause issues if #include <errno.h>
occurs before the library header inclusion. Another option is to compile the library with -D_REENTRANT
, and have the main header #error
if _REENTRANT
is not defined.
这导致了一个问题:如何通过头文件正确编译和分发线程安全库?一个选项是在主标题中#define _REENTRANT,但如果在包含库头之前发生#include
What's the correct/best way to make a thread-safe library and ensure it correctly inter-operates with the code it is linked with?
制作线程安全库并确保它与链接的代码正确互操作的正确/最佳方法是什么?
2 个解决方案
#1
4
I don't have access to any Solaris machine at the moment, so I can't test this. But what happens when you put #define _POSIX_C_SOURCE 200112L
as the very first line in test.c
(before inclusion of <errno.h>
)? If your Solaris is POSIX-compliant, then that should make errno
expand to the thread-safe version. This is because POSIX defines errno
as below:
我目前无权访问任何Solaris计算机,因此无法对此进行测试。但是当你将#define _POSIX_C_SOURCE 200112L作为test.c中的第一行(包含
For each thread of a process, the value of errno shall not be affected by function calls or assignments to errno by other threads.
对于进程的每个线程,errno的值不受其他线程的函数调用或对errno的赋值的影响。
Accordingly, this is portable to any POSIX-compliant system. In fact, if you want to write POSIX-compliant application code, then you should always define _POSIX_C_SOURCE
to the value appropriate for the minimum version of POSIX you are targeting. The definition should be at the top of every source file before including any headers. From the 2001 version of the standard:
因此,这可以移植到任何符合POSIX的系统。实际上,如果要编写符合POSIX的应用程序代码,则应始终将_POSIX_C_SOURCE定义为适合您所定位的最低POSIX版本的值。在包含任何标头之前,定义应位于每个源文件的顶部。从2001版标准:
A Strictly Conforming POSIX Application is an application that requires only the facilities described in IEEE Std 1003.1-2001. Such an application:
严格符合POSIX应用程序的应用程序仅需要IEEE Std 1003.1-2001中描述的功能。这样的申请:
...
8. For the C programming language, shall define _POSIX_C_SOURCE to be 200112L before any header is included
8.对于C编程语言,在包含任何头之前,应将_POSIX_C_SOURCE定义为200112L
#2
0
If your library uses autoconf, you probably want to use the AC_USE_SYSTEM_EXTENSIONS macro. That macro sets some target-specific defines which enable POSIX +extensions semantics. I don't have a Solaris system to test on at the moment, but I believe _POSIX_PTHREAD_SEMANTICS should enable the thread-safe errno. At least it enables the POSIX _r() functions rather than the POSIX-draft _r() variants which Solaris annoyingly provides by default.
如果您的库使用autoconf,您可能希望使用AC_USE_SYSTEM_EXTENSIONS宏。该宏设置了一些特定于目标的定义,这些定义启用了POSIX +扩展语义。我目前没有要测试的Solaris系统,但我相信_POSIX_PTHREAD_SEMANTICS应该启用线程安全的errno。至少它启用POSIX _r()函数而不是默认情况下Solaris烦人提供的POSIX-draft _r()变体。
#1
4
I don't have access to any Solaris machine at the moment, so I can't test this. But what happens when you put #define _POSIX_C_SOURCE 200112L
as the very first line in test.c
(before inclusion of <errno.h>
)? If your Solaris is POSIX-compliant, then that should make errno
expand to the thread-safe version. This is because POSIX defines errno
as below:
我目前无权访问任何Solaris计算机,因此无法对此进行测试。但是当你将#define _POSIX_C_SOURCE 200112L作为test.c中的第一行(包含
For each thread of a process, the value of errno shall not be affected by function calls or assignments to errno by other threads.
对于进程的每个线程,errno的值不受其他线程的函数调用或对errno的赋值的影响。
Accordingly, this is portable to any POSIX-compliant system. In fact, if you want to write POSIX-compliant application code, then you should always define _POSIX_C_SOURCE
to the value appropriate for the minimum version of POSIX you are targeting. The definition should be at the top of every source file before including any headers. From the 2001 version of the standard:
因此,这可以移植到任何符合POSIX的系统。实际上,如果要编写符合POSIX的应用程序代码,则应始终将_POSIX_C_SOURCE定义为适合您所定位的最低POSIX版本的值。在包含任何标头之前,定义应位于每个源文件的顶部。从2001版标准:
A Strictly Conforming POSIX Application is an application that requires only the facilities described in IEEE Std 1003.1-2001. Such an application:
严格符合POSIX应用程序的应用程序仅需要IEEE Std 1003.1-2001中描述的功能。这样的申请:
...
8. For the C programming language, shall define _POSIX_C_SOURCE to be 200112L before any header is included
8.对于C编程语言,在包含任何头之前,应将_POSIX_C_SOURCE定义为200112L
#2
0
If your library uses autoconf, you probably want to use the AC_USE_SYSTEM_EXTENSIONS macro. That macro sets some target-specific defines which enable POSIX +extensions semantics. I don't have a Solaris system to test on at the moment, but I believe _POSIX_PTHREAD_SEMANTICS should enable the thread-safe errno. At least it enables the POSIX _r() functions rather than the POSIX-draft _r() variants which Solaris annoyingly provides by default.
如果您的库使用autoconf,您可能希望使用AC_USE_SYSTEM_EXTENSIONS宏。该宏设置了一些特定于目标的定义,这些定义启用了POSIX +扩展语义。我目前没有要测试的Solaris系统,但我相信_POSIX_PTHREAD_SEMANTICS应该启用线程安全的errno。至少它启用POSIX _r()函数而不是默认情况下Solaris烦人提供的POSIX-draft _r()变体。