由于历史原因,标准C/C++库在开始时并没有正对多线程做考虑(比如使用了一些全局变量)
https://blog.csdn.net/syrchina/article/details/24657485
在 ARM 库中,函数可能是线程安全的,如下所示:
某些函数从来都不是线程安全的,例如 setlocale()
某些函数在本质上就是线程安全的,例如 memcpy()
某些函数(例如 malloc()
)可通过实现 _mutex_
* 函数变为线程安全的函数
其他函数仅在传递了适当参数时才是线程安全的,例如 tmpnam()
。
如果应用程序以隐藏方式使用 ARM 库(如使用语言辅助函数),则可能会出现线程问题。
线程安全的函数
Table 2.1 显示了线程安全的 C 库函数。
Table 2.1. 线程安全的函数
函数 | 说明 |
---|---|
calloc(), free(), malloc(), realloc() |
如果实现了 在所有线程之间共享单个堆,并使用互斥量以避免进行并发访问时发生数据损坏。每个堆实现都负责进行自己的锁定。 如果您提供了自己的分配器,它也必须进行自己的锁定。 这样,它便可进行精细锁定(如果需要),而不是简单地使用单个互斥量保护整个堆(粗放锁定)。 |
__alloca(), __alloca_finish(), __alloca_init(), __alloca_initialize() |
如果实现了 每个线程的 Note请注意, |
abort(), raise(), signal(), fenv.h |
ARM 信号处理函数和 FP 异常捕获是线程安全的。 信号处理程序和 FP 捕获设置是整个进程中的全局设置,并使用锁对其进行保护。 这样,即使多个线程同时调用 |
clearerr(), fclose(), feof(),ferror(), fflush(), fgetc(),fgetpos(), fgets(), fopen(),fputc(), fputs(), fread(),freopen(), fseek(), fsetpos(),ftell(), fwrite(), getc(),getchar(), gets(), perror(),putc(), putchar(), puts(),rewind(), setbuf(), setvbuf(),tmpfile(), tmpnam(), ungetc() |
如果实现了 每个单独的流都使用锁进行保护,因此,两个线程可以分别打开并使用其自己的 如果两个线程都要读取或写入相同的流, Note请注意, |
fprintf(), printf(), vfprintf(), vprintf(), fscanf(), scanf() |
使用这些函数时:
|
clock() |
clock() 包含程序静态数据,此数据是在启动时一次性写入的,以后只能对其进行读取。 因此,clock() 是线程安全的,但前提是在初始化库时没有运行任何其他线程。 |
errno() |
每个线程将其自己的 |
atexit() |
在最坏的情况下,如果多个线程调用 |
abs(), acos(), asin(),atan(), atan2(), atof(),atol(), atoi(), bsearch(),ceil(), cos(), cosh(),difftime(), div(), exp(),fabs(), floor(), fmod(),frexp(), labs(), ldexp(),ldiv(), log(), log10(),memchr(), memcmp(), memcpy(),memmove(), memset(), mktime(),modf(), pow(), qsort(),sin(), sinh(), sqrt(),strcat(), strchr(), strcmp(),strcpy(), strcspn(), strlcat(),strlcpy(), strlen(), strncat(),strncmp(), strncpy(), strpbrk(),strrchr(), strspn(), strstr(),strxfrm(), tan(), tanh() |
这些函数在本质上就是线程安全的。 |
longjmp(), setjmp() |
虽然 |
remove(), rename(), time() |
这些函数使用中断,以便与 ARM 调试环境进行通信。通常,必须为实际应用程序重新实现这些函数。 |
snprintf(), sprintf(), vsnprintf(),vsprintf(), sscanf(), isalnum(),isalpha(), iscntrl(), isdigit(),isgraph(), islower(), isprint(),ispunct(), isspace(), isupper(),isxdigit(), tolower(), toupper(),strcoll(), strtod(), strtol(),strtoul(), strftime() |
使用这些函数时,这些基于字符串的函数将读取语言环境。通常,它们是线程安全的。 但是,如果在会话中更改语言环境,则必须确保这些函数不受影响。 基于字符串的函数并不依赖于 |
stdin, stdout, stderr |
这些函数是线程安全的。 |
FP 状态字
可以在多线程环境(甚至软件浮点)中安全地使用 FP 状态字。 其中,每个线程的状态字存储在其自己的 __user_perthread_libspace
块中。
请注意,在硬件浮点中,FP 状态字存储在 VFP 寄存器中。 在这种情况下,线程切换机制必须为每个线程保留该寄存器的单独副本。
非线程安全的函数
Table 2.2 显示了非线程安全的 C 库函数。
Table 2.2. 非线程安全的函数
函数 | 说明 |
---|---|
setlocale() |
语言环境设置是所有线程的全局设置,并且未使用锁对其进行保护。如果两个线程调用 ARM 建议您选择所需的语言环境,然后调用一次 请注意, |
asctime(), localtime(), strtok() |
这些函数不是线程安全的。 每个函数都包含一个静态缓冲区,其他线程可能会在调用函数以及随后使用其返回值之间覆盖该缓冲区。 ARM 提供了可重入版本 Note这些可重入版本使用一些附加参数。 |
gamma()[1], lgamma() |
这些扩展 mathlib 函数使用全局变量 _signgam ,因此不是线程安全的。 |
mbrlen(), mbsrtowcs(), mbrtowc(),wcrtomb(), wcsrtombs() |
但是, |
exit() |
即使提供了基本 在这种情况下, |
rand(), srand() |
这些函数保留全局性且不受保护的内部状态。 这意味着, ARM 建议您使用自己的锁定,以确保每次只有一个线程调用 或者,也可以执行以下操作之一:
|
[1] 已不提倡使用 |