errno 是线程安全的吗?
- 2024-10-10 09:28:00
- admin 原创
- 79
问题描述:
在 中errno.h
,此变量被声明为extern int errno;
,所以我的问题是,在多线程代码中,在一些调用之后检查值或使用 perror() 是否安全errno
。这是一个线程安全变量吗?如果不是,那么有什么替代方案?
我在 x86 架构上使用带有 gcc 的 linux。
解决方案 1:
是的,它是线程安全的。在 Linux 上,全局 errno 变量是线程特定的。POSIX 要求 errno 是线程安全的。
请参阅http://www.unix.org/whitepapers/reentrant.html
在 POSIX.1 中,errno 被定义为外部全局变量。但这种定义在多线程环境中是不可接受的,因为使用 errno 可能会导致不确定的结果。问题是两个或多个线程可能会遇到错误,所有错误都会导致设置相同的 errno。在这种情况下,一个线程可能会在另一个线程已经更新 errno 之后才检查它。
为了避免由此产生的不确定性,POSIX.1c 将 errno 重新定义为可以访问每个线程错误号的服务,如下所示(ISO/IEC 9945:1-1996,§2.4):
某些函数可能会在通过符号 errno 访问的变量中提供错误编号。符号 errno 的定义方式是包含标头,如 C 标准所指定...对于进程的每个线程,errno 的值不应受到其他线程的函数调用或对 errno 的赋值的影响。
另请参阅http://linux.die.net/man/3/errno
errno 是线程局部的;在一个线程中设置它不会影响任何其他线程中的值。
解决方案 2:
是的
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 ())); }
$
解决方案 3:
是的,正如errno 手册页和其他回复中所解释的那样,errno 是一个线程局部变量。
然而,有一个细节很容易被遗忘。程序应该在执行系统调用的任何信号处理程序上保存和恢复 errno。这是因为该信号将由可能覆盖其值的进程线程之一处理。
因此,信号处理程序应该保存并恢复 errno。例如:
void sig_alarm(int signo)
{
int errno_save;
errno_save = errno;
//whatever with a system call
errno = errno_save;
}
解决方案 4:
我们可以通过在机器上运行一个简单的程序来检查。
#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
", 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
请注意,所有线程的地址都是不同的。
解决方案 5:
在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
解决方案 6:
这是<sys/errno.h>
在我的 Mac 上拍摄的:
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int * __error(void);
#define errno (*__error())
__END_DECLS
所以errno
现在是一个函数__error()
。该函数的实现是线程安全的。
解决方案 7:
在许多 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) */
解决方案 8:
我认为答案是“视情况而定”。如果您使用正确的标志构建线程代码,线程安全 C 运行时库通常会将 errno 实现为函数调用(宏扩展为函数)。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件