标题:全局变量errno: Thread-Local Storage 出处:Felix021 时间:Tue, 27 Jul 2010 22:50:29 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?1898 内容: 在ISO C规范中有有一个很诡异的东西,那就是传说中的errno,一个有左值的int。当库函数出错的时候,它很可能会被设置为非0值;且没有任何一个库函数或系统调用会把它置为0。 刚接触到errno,可能会认为这是个在errno.h中用int errno; 定义的整型。但是一旦开始写多线程的程序,再看到errno的时候,就会抑郁了。如果两个线程调用库函数都出错,那errno怎么办...? 幸而,ISO C并没有规定,errno必须是一个int,如果看errno的manpage (man errno) 会看到:引用 errno may be a macro. errno is thread-local; setting it in one thread does not affect its value in any other thread. 实际上GNU的glibc也就是这么实现的,(通常)在/usr/include/bits/errno.h里头:#define errno (*__errno_location ()) 于是errno就是个有左值的int了。至于这个__errno_location,在glibc的源码的 csu/errno-loc.c 里头:int * #if ! USE___THREAD weak_const_function #endif __errno_location (void) { return &errno; } 而这里的真正的errno,在 csu/errno.c 里头:__thread int errno; 由于包含的都是errno.h,所以对于用户程序而言,可见的只有errno.h中的"errno",实际上是(*(__errno_location()),而__errno_location()返回的是errno.c中的errno的地址。可真绕啊。可是偏偏又不能把 __thread int errno; 放在errno.h中,为什么呢?其实原因很简单也很复杂——C语言真是个纠结的语言。 最后,解释一下“__thread”修饰符:__thread defines number to be a thread local variable. 定义thread-local的变量。详情参见Thread-local_storage的wiki页:http://en.wikipedia.org/wiki/Thread-local_storage Generated by Bo-blog 2.1.0