如果#define替换errno符号,如何初始化线程安全errno?

时间:2013-08-02 20:56:36

标签: c thread-safety c99 glibc errno

我试图了解 glibc 如何在没有预处理器替换errno符号的情况下初始化errno

我首先尝试根据csu/errno-loc.ccsu/errno.c自行实现一个简单版本:

myerrno.h

#ifndef MYERRNO_H
#define MYERRNO_H

extern int *myerrno_location(void);
#define myerrno (*myerrno_location())

#endif

myerrno.c

#include "myerrno.h"

static int myerrno = 0;

int *myerrno_location(void){
    return &myerrno;
}

但是,当我尝试编译时,收到以下错误消息:

myerrno.c:3:1: error: function ‘myerrno_location’ is initialized like a variable
myerrno.c:3:12: error: static declaration of ‘myerrno_location’ follows non-static declaration
myerrno.h:4:13: note: previous declaration of ‘myerrno_location’ was here

我可以说,预处理器在第3行遇到(*myerrno_location(void))时会替换myerrno - 自然这是预期的行为。

我不明白为什么这对 glibc 来说不是问题。 errno的线程安全实现如何解决这个预处理器替换问题而不重命名静态errno变量?

1 个答案:

答案 0 :(得分:3)

修复问题就像更改静态变量的名称一样简单。

static int myerrno_variable = 0;

int *myerrno_location(void){
    return &myerrno_variable;
}

请注意,由于所有线程都访问相同的myerrno_variable,因此您的版本仍然不是线程安全的。真正的实现将返回特定于线程的内存位置。在GCC中,有一个提供__thread存储类的扩展。 C.11提供了自己的版本,称为thread_local,但只有在实现提供线程支持时才可用(可以通过查看是否定义了__STDC_NO_THREADS__来检查)。

static __thread int myerrno_variable_gcc;      /* if using GCC */
static thread_local int my_errno_variable_c11; /* if __STD_NO_THREADS__ isn't defined */

在没有线程本地功能的POSIX系统上,实现可以使用pthread_getspecific()来获取指向为每个线程分配的线程特定数据的指针,并使用pthread_setspecific()进行设置。有关详细信息,请参阅the manual