はい、スレッドセーフです。 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