在errno.h中,这个变量被声明为extern int errno;所以我的问题是,在一些调用后检查errno值或在多线程代码中使用perror()是否安全。这是线程安全的变量吗?如果不是,那么有什么替代方案?
我在x86架构上使用gcc linux。
在errno.h中,这个变量被声明为extern int errno;所以我的问题是,在一些调用后检查errno值或在多线程代码中使用perror()是否安全。这是线程安全的变量吗?如果不是,那么有什么替代方案?
我在x86架构上使用gcc linux。
当前回答
是的,正如errno手册页和其他回复中解释的那样,errno是一个线程局部变量。
然而,有一个很容易被遗忘的愚蠢细节。程序应该在执行系统调用的任何信号处理程序上保存和恢复errno。这是因为信号将由一个进程线程处理,该进程线程可以覆盖其值。
因此,信号处理程序应该保存并恢复errno。喜欢的东西:
void sig_alarm(int signo)
{
int errno_save;
errno_save = errno;
//whatever with a system call
errno = errno_save;
}
其他回答
这是来自<sys/errno.h>在我的Mac:
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int * __error(void);
#define errno (*__error())
__END_DECLS
所以errno现在是一个__error()函数。函数的实现是线程安全的。
在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
是的,正如errno手册页和其他回复中解释的那样,errno是一个线程局部变量。
然而,有一个很容易被遗忘的愚蠢细节。程序应该在执行系统调用的任何信号处理程序上保存和恢复errno。这是因为信号将由一个进程线程处理,该进程线程可以覆盖其值。
因此,信号处理程序应该保存并恢复errno。喜欢的东西:
void sig_alarm(int signo)
{
int errno_save;
errno_save = errno;
//whatever with a system call
errno = errno_save;
}
是的,它是线程安全的。在Linux上,全局errno变量是特定于线程的。POSIX要求errno是线程安全的。
参见http://www.unix.org/whitepapers/reentrant.html
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 , 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.
参见http://linux.die.net/man/3/errno
Errno是线程本地的;在一个线程中设置它不会影响它在其他线程中的值。
Yes
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 ())); }
$