在errno.h中,这个变量被声明为extern int errno;所以我的问题是,在一些调用后检查errno值或在多线程代码中使用perror()是否安全。这是线程安全的变量吗?如果不是,那么有什么替代方案?
我在x86架构上使用gcc linux。
在errno.h中,这个变量被声明为extern int errno;所以我的问题是,在一些调用后检查errno值或在多线程代码中使用perror()是否安全。这是线程安全的变量吗?如果不是,那么有什么替代方案?
我在x86架构上使用gcc linux。
当前回答
我们可以在机器上运行一个简单的程序来检查。
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#define NTHREADS 5
void *thread_function(void *);
int
main()
{
pthread_t thread_id[NTHREADS];
int i, j;
for(i=0; i < NTHREADS; i++)
{
pthread_create( &thread_id[i], NULL, thread_function, NULL );
}
for(j=0; j < NTHREADS; j++)
{
pthread_join( thread_id[j], NULL);
}
return 0;
}
void *thread_function(void *dummyPtr)
{
printf("Thread number %ld addr(errno):%p\n", pthread_self(), &errno);
}
运行这个程序,您可以在每个线程中看到errno的不同地址。在我的机器上运行的输出看起来像:-
Thread number 140672336922368 addr(errno):0x7ff0d4ac0698
Thread number 140672345315072 addr(errno):0x7ff0d52c1698
Thread number 140672328529664 addr(errno):0x7ff0d42bf698
Thread number 140672320136960 addr(errno):0x7ff0d3abe698
Thread number 140672311744256 addr(errno):0x7ff0d32bd698
注意,所有线程的地址都是不同的。
其他回答
是的,它是线程安全的。在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 ())); }
$
我认为答案是“视情况而定”。线程安全的C运行时库通常将errno实现为函数调用(宏扩展为函数),如果您正在使用正确的标志构建线程代码。
在许多Unix系统上,使用-D_REENTRANT编译可以确保errno是线程安全的。
例如:
#if defined(_REENTRANT) || _POSIX_C_SOURCE - 0 >= 199506L
extern int *___errno();
#define errno (*(___errno()))
#else
extern int errno;
/* ANSI C++ requires that errno be a macro */
#if __cplusplus >= 199711L
#define errno errno
#endif
#endif /* defined(_REENTRANT) */
这是来自<sys/errno.h>在我的Mac:
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int * __error(void);
#define errno (*__error())
__END_DECLS
所以errno现在是一个__error()函数。函数的实现是线程安全的。