繁体   English   中英

构建线程安全的多平台C库的正确方法是什么?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM