GNU/Linux >> Linux の 問題 >  >> Linux

errno はスレッドセーフですか?

はい、スレッドセーフです。 Linux では、グローバル errno 変数はスレッド固有です。 POSIX では、errno がスレッドセーフである必要があります。

http://www.unix.org/whitepapers/reentrant.html を参照

<ブロック引用>

POSIX.1 では、errno は外部グローバル変数として定義されています。ただし、この定義はマルチスレッド環境では受け入れられません。これを使用すると非決定論的な結果が生じる可能性があるためです。問題は、2 つ以上のスレッドでエラーが発生し、すべて同じ errno が設定される可能性があることです。このような状況では、別のスレッドによって既に更新された後に、スレッドが errno をチェックすることになる可能性があります。

結果として生じる非決定性を回避するために、POSIX.1c は、スレッドごとのエラー番号にアクセスできるサービスとして serrno を次のように再定義します (ISO/IEC 9945:1-1996、§2.4):

一部の関数は、シンボル errno を介してアクセスされる変数にエラー番号を提供する場合があります。シンボル errno は、C 標準で指定されているように、header を含めることによって定義されます。プロセスの各スレッドについて、errno の値は、他のスレッドによる関数呼び出しまたは errno への代入の影響を受けません。

http://linux.die.net/man/3/errno も参照してください

<ブロック引用>

errno はスレッドローカルです。あるスレッドで設定しても、他のスレッドの値には影響しません。


はい

Errno はもはや単純な変数ではありません。特にスレッドセーフにするために、舞台裏で複雑なものになっています。

$ man 3 errno を参照 :

ERRNO(3)                   Linux Programmer’s Manual                  ERRNO(3)

NAME
       errno - number of last error

SYNOPSIS
       #include <errno.h>

DESCRIPTION

      ...
       errno is defined by the ISO C standard to be  a  modifiable  lvalue  of
       type  int,  and  must not be explicitly declared; errno may be a macro.
       errno is thread-local; setting it in one thread  does  not  affect  its
       value in any other thread.

再確認できます:

$ cat > test.c
#include <errno.h>
f() { g(errno); }
$ cc -E test.c | grep ^f
f() { g((*__errno_location ())); }
$ 

<ブロック引用>

errno.h では、この変数は extern int errno として宣言されています。

C 標準の内容は次のとおりです。

<ブロック引用>

マクロ errno オブジェクトの識別子である必要はありません。関数呼び出しの結果、変更可能な左辺値に展開される場合があります (例:*errno() ).

通常、errno 現在のスレッドのエラー番号のアドレスを返す関数を呼び出し、それを逆参照するマクロです。

これが Linux の /usr/include/bits/errno.h にあります:

/* Function to get address of global `errno' variable.  */
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

最終的に、次のようなコードが生成されます:

> cat essai.c
#include <errno.h>

int
main(void)
{
    errno = 0;

    return 0;
}
> gcc -c -Wall -Wextra -pedantic essai.c
> objdump -d -M intel essai.o

essai.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
   0: 55                    push   ebp
   1: 89 e5                 mov    ebp,esp
   3: 83 e4 f0              and    esp,0xfffffff0
   6: e8 fc ff ff ff        call   7 <main+0x7>  ; get address of errno in EAX
   b: c7 00 00 00 00 00     mov    DWORD PTR [eax],0x0  ; store 0 in errno
  11: b8 00 00 00 00        mov    eax,0x0
  16: 89 ec                 mov    esp,ebp
  18: 5d                    pop    ebp
  19: c3                    ret

Linux
  1. C プログラムでスレッドを終了する方法 ( pthread_exit の例 )

  2. Linuxでスレッドに名前を付ける方法は?

  3. スレッドには個別のヒープがありますか?

  1. pthread_t を出力する方法

  2. strtok 関数のスレッド セーフ

  3. スレッド ID とスレッド ハンドル

  1. スレッド内からフォークしても安全ですか?

  2. 新しいコンソール ウィンドウで Python スレッドを開く

  3. どのスレッドがシグナルを処理しますか?