使用pthread实现errno analogue

时间:2014-01-15 12:46:52

标签: c pthreads errno

正如$ man errno所说,“errno被ISO C标准定义为int类型的可修改左值,不能显式声明; errno可能是宏.errno是线程本地的;设置它在一个线程中不会影响其在任何其他线程中的值“。

我正在开发一个可以在POSIX和Windows中运行的C库,所以我决定坚持自己的错误类型,而不是使用errnoGetLastError/SetLastError。我的每个函数都将错误代码作为cg_error对象返回,其中cg_error只是一个typedef。但是,对于某些功能(如自定义分配器),最好使用errno之类的功能,但使用我自己的cg_error类型。


glibc中的AFAIK errno以这种方式实现:

#define errno (*__errno_location ())


我正在尝试使用Linux上的pthreadsTlsAlloc以及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

1 个答案:

答案 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);
  ...

}