首先,我知道
strsignal()
不是线程安全的一般原因是标准说它可能不是。
strsignal()
GNU C 标准库函数是在 POSIX 规范中定义的,在该规范中它说:
strsignal() 函数不需要是线程安全的。
https://pubs.opengroup.org/onlinepubs/9699919799.2016edition/functions/strsignal.html
由于标准不要求
strsignal()
是线程安全的,因此使用此函数的代码
不能假设它是线程安全的,除非使用的特定实现指定它是线程安全的。
例如,POSIX 规范规定
strerror()
可能不是线程安全的,但 glibc 2.32 中的更改意味着在较新版本的 glibc 中,此函数现在是线程安全的,并且在 man 3 strerror
上如此列出。
https://lists.gnu.org/archive/html/info-gnu/2020-08/msg00002.html
GNU linux 版本的 C 标准库函数
strsignal()
的手册页指定该函数是线程不安全的:
Linux 手册页 6.7
man 3 strsignal
┌───────────────────────────────┬───────────────┬─────────────────────────────────┐
│ Interface │ Attribute │ Value │
├───────────────────────────────┼───────────────┼─────────────────────────────────┤
│ strsignal() │ Thread safety │ MT-Unsafe race:strsignal locale │
├───────────────────────────────┼───────────────┼─────────────────────────────────┤
│ sigdescr_np(), sigabbrev_np() │ Thread safety │ MT-Safe │
└───────────────────────────────┴───────────────┴─────────────────────────────────┘
但是,查看源代码可以发现,专门针对 glibc 表明,自 2.32 起
strsignal()
使用了线程本地缓冲区,我认为这使其成为线程安全的。
https://elixir.bootlin.com/glibc/glibc-2.32/source/string/strsignal.c#L27
那么,从 glibc 2.32 开始,为什么
strerror()
被认为是 MT 安全的,但 strsignal()
仍然是
此处记录为 MT-不安全?
源代码还显示,
strsignal()
没有特定于区域设置的绑定,尽管文档称可能存在区域设置线程竞争。这是未来可能发生的变化的证明吗?
首先,您需要认识到 GLIBC 和手册页是完全独立的项目。
文档可能不正确或过时(欢迎补丁)。
其次,
strsignal
使用线程本地缓冲区这一事实本身并不能保证线程安全。所有 strsignal
调用也必须是线程安全的。“区域设置竞赛”评论意味着
输出受语言环境影响