Ale*_*sky 10 c gcc pthreads thread-safety
考虑以下简单的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 <errno.h>在包含库头之前发生这将导致问题.另一种选择是使用编译库-D_REENTRANT,#error如果_REENTRANT没有定义,则使用主标题.
制作线程安全库并确保它与链接的代码正确互操作的正确/最佳方法是什么?
我目前无法访问任何 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