Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C errno全局变量是否是线程安全的 #138

zhangyachen opened this issue Dec 2, 2018 · 0 comments


None yet
1 participant
Copy link

commented Dec 2, 2018


for(int i=0;i<THREADNUM;i++){

    connfd = accept(listenfd,(struct sockaddr *)&clientaddr,&clientlen);
    sbuf_insert(&buf,connfd);      //put connfd into pool

void *start_routine(void *argv){
    int connfd;
    int p = pthread_detach(pthread_self());
        connfd = sbuf_remove(&buf);        //thread get connfd
        doit(connfd);         //what if doit set global variable errno 

    return NULL;

关于C中错误处理的问题,可以参考Error Handling in C programs,简单的说很多系统调用只会返回成功或者失败,具体失败的原因会设置全局变量errno供调用方自己读取,所以引发了多线程里errno线程安全的问题。

Redefinition of errno
In POSIX.1, errno is defined as an external global variable. But this definition is unacceptable in a multithreaded environment, because its use can result in nondeterministic results. The problem is that two or more threads can encounter errors, all causing the same errno to be set. Under these circumstances, a thread might end up checking errno after it has already been updated by another thread.
To circumvent the resulting nondeterminism, POSIX.1c redefines errno as a service that can access the per-thread error number as follows (ISO/IEC 9945:1-1996, §2.4):
Some functions may provide the error number in a variable accessed through the symbol errno. The symbol errno is defined by including the header <errno.h>, as specified by the C Standard ... For each thread of a process, the value of errno shall not be affected by function calls or assignments to errno by other threads.



/* Declare the `errno' variable, unless it's defined as a macro by
   bits/errno.h.  This is the case in GNU, where it is a per-thread
   variable.  This redeclaration using the macro still works, but it
   will be a function declaration without a prototype and may trigger
   a -Wstrict-prototypes warning.  */
#ifndef errno
extern int errno;



extern int *__errno_location (void) __THROW __attribute__ ((__const__));

#  if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value.  */
#   define errno (*__errno_location ())
#  endif

可以清晰的看到,bits/errno.h对errno进行了重定义。从 __attribute__ ((__const__))推测出__errno_location ()会返回与参数无关的与线程绑定的一个特定地址,应用层直接从该地址取出errno的。(关于__attribute__用法可以参考Using GNU C attribute)。但是上面使用了条件编译,也就是有两种方法可以使得gcc重定义errno:

  • 不定义宏_LIBC


gcc -D_LIBC a.c
In file included from /usr/include/gnu/stubs.h:9:0,
                 from /usr/include/features.h:385,
                 from /usr/include/stdio.h:28,
                 from a.c:1:
/usr/include/gnu/stubs-64.h:7:3: error: #error Applications may not define the macro _LIBC
  #error Applications may not define the macro _LIBC


#ifdef _LIBC
 #error Applications may not define the macro _LIBC


#include <stdio.h>
#include <errno.h>

int main(){

    int i = errno;

    return 0;


0x0000000000400588 in main ()
=> 0x0000000000400588 <main+8>: e8 7b fe ff ff  callq  0x400408 <__errno_location@plt>


0x0000003dc8e148c0 in _dl_runtime_resolve () from /lib64/
=> 0x0000003dc8e148c0 <_dl_runtime_resolve+0>:  48 83 ec 38     sub    $0x38,%rsp



void handle_signal(int sig){
    int savedErrno;
    savedErrno = errno;
    /* Do something when recevied this sig */

    errno = savedErrno;


@zhangyachen zhangyachen added the C label Dec 2, 2018

@zhangyachen zhangyachen changed the title C errno是否是线程安全的 C errno全局变量是否是线程安全的 Dec 2, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.