首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ARM C 库中的线程安全性(1)

ARM C 库中的线程安全性(1)

在 ARM 库中,函数可能是线程安全的,如下所示:
  • 某些函数从来都不是线程安全的,例如 setlocale()
  • 某些函数在本质上就是线程安全的,例如 memcpy()
  • 某些函数(例如 malloc())可通过实现 _mutex_* 函数变为线程安全的函数
  • 其他函数仅在传递了适当参数时才是线程安全的,例如 tmpnam()。

如果应用程序以隐藏方式使用 ARM 库(如使用语言辅助函数),则可能会出现线程问题。
线程安全的函数
Table 2.1 显示了线程安全的 C 库函数。
Table 2.1. 线程安全的函数
函数说明calloc(),free(),malloc(),realloc()如果实现了 _mutex_* 函数,则堆函数是线程安全的。
在所有线程之间共享单个堆,并使用互斥量以避免进行并发访问时发生数据损坏。每个堆实现都负责进行自己的锁定。 如果您提供了自己的分配器,它也必须进行自己的锁定。 这样,它便可进行精细锁定(如果需要),而不是简单地使用单个互斥量保护整个堆(粗放锁定)。
__alloca(),__alloca_finish(),__alloca_init(),__alloca_initialize()如果实现了 _mutex_* 函数,则 alloca 函数是线程安全的。
每个线程的 alloca 状态包含在 __user_perthread_libspace 块中。这意味着多个线程不会发生冲突。
Note请注意,alloca 函数也使用堆。 不过堆函数都是线程安全的。

abort(),raise(),signal(),fenv.hARM 信号处理函数和 FP 异常捕获是线程安全的。
信号处理程序和 FP 捕获设置是整个进程中的全局设置,并使用锁对其进行保护。 这样,即使多个线程同时调用 signal() 或 fenv.h 函数,也不会损坏数据。但要注意,调用影响所有线程,而不是只影响调用线程。
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()如果实现了 _mutex_* 函数,则 stdio 库是线程安全的。
每个单独的流都使用锁进行保护,因此,两个线程可以分别打开并使用其自己的 stdio流,而不会相互干扰。
如果两个线程都要读取或写入相同的流,fgetc() 和 fputc() 级别的锁定可防止发生数据损坏,但是,每个线程的单独字符输出可能会交叉出现,因而容易造成混淆。
Note请注意,tmpnam() 也包含一个静态缓冲区,但仅在自变量为 NULL 时才使用它。 要确保 tmpnam() 使用是线程安全的,应提供您自己的缓冲区空间。

fprintf(), printf(),vfprintf(), vprintf(), fscanf(),scanf()使用这些函数时:
  • 标准 C printf() 和 scanf() 函数使用 stdio,因而是线程安全的。
  • 如果在多线程程序中调用标准 C printf(),其语言环境可能会发生变化。

clock()clock() 包含程序静态数据,此数据是在启动时一次性写入的,以后只能对其进行读取。 因此,clock() 是线程安全的,但前提是在初始化库时没有运行任何其他线程。errno()errno 是线程安全的。
每个线程将其自己的 errno 存储在 __user_perthread_libspace 块中。这意味着,每个线程可以单独调用 errno 设置函数,然后检查 errno,而不用担心受其他线程的影响。
atexit()atexit() 维护的退出函数列表是进程全局性的,并且使用锁对其进行保护。
在最坏的情况下,如果多个线程调用 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()虽然 setjmp() 和 longjmp() 在 __user_libspace 中保存数据,但它们均调用线程安全的 __alloca_* 函数。
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()使用这些函数时,这些基于字符串的函数将读取语言环境。通常,它们是线程安全的。 但是,如果在会话中更改语言环境,则必须确保这些函数不受影响。
基于字符串的函数并不依赖于 stdio 库,例如,sprintf() 和 sscanf()。
stdin, stdout, stderr这些函数是线程安全的。


FP 状态字
可以在多线程环境(甚至软件浮点)中安全地使用 FP 状态字。 其中,每个线程的状态字存储在其自己的__user_perthread_libspace 块中。
Note请注意,在硬件浮点中,FP 状态字存储在 VFP 寄存器中。 在这种情况下,线程切换机制必须为每个线程保留该寄存器的单独副本。


继承事业,薪火相传
返回列表