[英]What is the correct way to build a thread-safe, multiplatform C library?
考虑以下简单的C程序,
#include <errno.h>
int
main(int argc, char* argv[]) {
return errno;
}
在Solaris上编译时,此代码的行为取决于-D_REENTRANT
的存在。
solaris$ cc -E test.c | grep return
return errno;
solaris$ cc -D_REENTRANT -E test.c | grep return
return ( * ( ___errno ( ) ) );
后一版本是线程安全的。 如果我们在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
具有选项-mt
,这意味着-D_REENTRANT
一样, gcc
的-pthread
。 但是,对于库,指定这些多线程选项似乎很差,因为它会对线程运行时注入不必要的依赖。 但是,如果库需要是线程安全的(包括errno),那么在库的编译时和派生代码的编译时都需要线程安全的语义。 在Linux上,这很容易,因为errno总是线程局部的,但是在其他系统上并不能保证这一点。
这导致了一个问题:如何正确编译线程安全的库并使用头文件进行分发? 一个选项是在主标题中#define _REENTRANT
,但如果在包含库头之前发生#include <errno.h>
,这将导致问题。 另一种选择是使用-D_REENTRANT
编译库,如果未定义_REENTRANT
则使用主标题#error
。
制作线程安全库并确保它与链接的代码正确互操作的正确/最佳方法是什么?
我目前无权访问任何Solaris计算机,因此无法对此进行测试。 但是当你将#define _POSIX_C_SOURCE 200112L
作为test.c
第一行(包含<errno.h>
)时会发生什么? 如果您的Solaris符合POSIX,那么应该将errno
扩展为线程安全版本。 这是因为POSIX定义了errno
,如下所示:
对于进程的每个线程, errno的值不受其他线程的函数调用或对errno的赋值的影响。
因此,这可以移植到任何符合POSIX的系统。 实际上,如果要编写符合POSIX的应用程序代码,则应始终将_POSIX_C_SOURCE
定义为适合您所定位的最低POSIX版本的值。 在包含任何标头之前,定义应位于每个源文件的顶部。 从2001版标准:
严格符合POSIX应用程序的应用程序仅需要IEEE Std 1003.1-2001中描述的功能。 这样的申请:
...
8.对于C编程语言,在包含任何头之前,应将_POSIX_C_SOURCE定义为200112L
如果您的库使用autoconf,您可能希望使用AC_USE_SYSTEM_EXTENSIONS宏。 该宏设置了一些特定于目标的定义,这些定义启用了POSIX +扩展语义。 我目前没有要测试的Solaris系统,但我相信_POSIX_PTHREAD_SEMANTICS应该启用线程安全的errno。 至少它启用POSIX _r()函数而不是默认情况下Solaris烦人提供的POSIX-draft _r()变体。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.