【发布时间】:2013-04-11 09:01:38
【问题描述】:
考虑以下琐碎的 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。
制作线程安全库并确保它与链接的代码正确互操作的正确/最佳方法是什么?
【问题讨论】:
标签: c gcc thread-safety pthreads