正如$ man errno
所说,“errno被ISO C标准定义为int类型的可修改左值,不能显式声明; errno可能是宏.errno是线程本地的;设置它在一个线程中不会影响其在任何其他线程中的值“。
我正在开发一个可以在POSIX和Windows中运行的C库,所以我决定坚持自己的错误类型,而不是使用errno
和GetLastError/SetLastError
。我的每个函数都将错误代码作为cg_error
对象返回,其中cg_error
只是一个typedef。但是,对于某些功能(如自定义分配器),最好使用errno
之类的功能,但使用我自己的cg_error
类型。
glibc中的AFAIK errno以这种方式实现:
#define errno (*__errno_location ())
我正在尝试使用Linux上的pthreads
和TlsAlloc
以及Windows上的朋友来实现类似的功能。这就是我现在所拥有的(但是只有POSIX,似乎是来自Web上的文章“特定于线程的存储模式”的Solaris实现):
cg_error * CG_ERRNO_TLS(void)
{
#if CG_FEATURE_POSIX
static int once;
static pthread_key_t key;
static pthread_mutex_t lock;
cg_error * error = NULL;
if (once)
{
pthread_mutex_lock(&lock);
if (once)
{
(void) pthread_key_create(&key, cg_free);
once = 1;
}
pthread_mutex_unlock(&lock);
}
error = pthread_getspecific(key);
if (!error)
{
error = cg_malloc(sizeof(*error));
(void) pthread_setspecific(key, error);
}
return error;
#endif
}
#define cg_errno (*CG_ERRNO_TLS())
但是,当我尝试设置或获取cg_errno
时,其int值为6344768
,这不是我想要的。我究竟做错了什么?什么是定义errno
之类的正确方法?提前谢谢!
PS 我知道我可以使用__thread
和__declspec(thread)
,但这些事情是特定于编译器的(可能是系统特定的;我听说{{1}例如对于带有gcc的MacOSX,它不起作用。
P.P.S。 __thread
的基值为cg_error
,始终为0.
的更新:
CG_ERROR_NONE
答案 0 :(得分:3)
once
的条件错误。它应该是!once
。
但是使用int
并不能保证能够正常工作。对于您要尝试实现的任务,有一个特殊类型pthread_once_t
,其函数为pthread_once
。
此外,lock
应该有一个初始化程序PTHREAD_MUTEX_INITIALIZER
。
使用pthread_once_t
看起来像这样:
static pthread_key_t key;
static pthread_once_t once = PTHREAD_ONCE_INIT;
static
void init_error_key_once(void) {
pthread_key_create(&key, cg_free);
}
cg_error * CG_ERRNO_TLS_POSIX(void)
{
cg_error * error = NULL;
pthread_once(&once, init_error_key_once);
...
}