我正在将 getaddrinfo 用于与 IPv6 相关的 C 项目。我电脑上的“man getaddrinfo”(uname -a: 3.5.0-23)只表示它是“可重入的”。所以我猜它不是线程安全的。
在需要线程安全的场景下,如何处理?我还检查了 UNP,但似乎没有提供具体答案。非常感谢。
我正在将 getaddrinfo 用于与 IPv6 相关的 C 项目。我电脑上的“man getaddrinfo”(uname -a: 3.5.0-23)只表示它是“可重入的”。所以我猜它不是线程安全的。
在需要线程安全的场景下,如何处理?我还检查了 UNP,但似乎没有提供具体答案。非常感谢。
getaddrinfo()
确实是线程安全的。这是RFC 3493 第 6.1 节要求的:
函数 getaddrinfo() 和 freeaddrinfo() 必须是线程安全的。
在某些平台上,gethostbyname()
它是线程安全的,但在其他平台上则不是。gethostbyname()
不在所有平台上的都是可重入的。如果您在同一个线程中调用gethostbyname()
然后gethostbyname()
再次调用,则第一次调用的数据将被第二次调用的数据覆盖。这是因为gethostbyname()
通常在内部使用静态缓冲区,这就是为什么您必须在再次调用之前复制数据gethostbyname()
。getaddrinfo()
不会遇到这个问题,因为它addrinfo
每次调用时都会分配一个新结构。
好吧,getaddrinfo 在某些平台上不是线程安全的,例如 Linux:http: //man7.org/linux/man-pages/man3/getaddrinfo.3.html
┌────────────────┬───────────────┬────────────────────┐
│Interface │ Attribute │ Value │
├────────────────┼───────────────┼────────────────────┤
│getaddrinfo() │ Thread safety │ MT-Safe env locale │
├────────────────┼───────────────┼────────────────────┤
│freeaddrinfo(), │ Thread safety │ MT-Safe │
│gai_strerror() │ │ │
└────────────────┴───────────────┴────────────────────┘
注意 env 和 locale 属性:
Other safety remarks
Additional keywords may be attached to functions, indicating features
that do not make a function unsafe to call, but that may need to be
taken into account in certain classes of programs:
locale Functions annotated with locale as an MT-Safety issue read
from the locale object without any form of synchronization.
Functions annotated with locale called concurrently with
locale changes may behave in ways that do not correspond to
any of the locales active during their execution, but an
unpredictable mix thereof.
We do not mark these functions as MT-Unsafe, however, because
functions that modify the locale object are marked with
const:locale and regarded as unsafe. Being unsafe, the latter
are not to be called when multiple threads are running or
asynchronous signals are enabled, and so the locale can be
considered effectively constant in these contexts, which makes
the former safe.
env Functions marked with env as an MT-Safety issue access the
environment with getenv(3) or similar, without any guards to
ensure safety in the presence of concurrent modifications.
We do not mark these functions as MT-Unsafe, however, because
functions that modify the environment are all marked with
const:env and regarded as unsafe. Being unsafe, the latter
are not to be called when multiple threads are running or
asynchronous signals are enabled, and so the environment can
be considered effectively constant in these contexts, which
makes the former safe.
所以如果不考虑它,你会得到随机的段错误。有关详细信息,请参阅此旧 glibc 错误讨论:https ://sourceware.org/bugzilla/show_bug.cgi?id=13271
getaddrinfo() 是线程安全的。所有(或几乎所有)函数手册页都有关于线程安全的信息。Reentrant
表示线程安全。
getaddrinfo()
是 POSIX 标准的一部分,POSIX 标准要求:
freeaddrinfo() 和 getaddrinfo() 函数应该是线程安全的。
来源: http: //pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html
如果不是这种情况,操作系统可能不会声称符合 POSIX。
您可能听说过的符合 POSIX 的正式操作系统:
AIX、BSD、IRIX、macOS、(Open)Solaris、QNX 以及其他几个。
在这些平台上,您可以依赖getaddrinfo()
线程安全。
众所周知的操作系统并未正式符合 POSIX,但始终试图尽可能接近 POSIX 标准以实现软件兼容性:
BeOS、FreeBSD、GNU、iOS、Linux、NetBSD、OpenBSD 以及其他几个。
在这些平台上,您不能完全依赖于getaddrinfo()
线程安全,但您当然可以期望它足够线程安全,以便您可以在应用程序中的多个线程中使用它,而无需对其进行任何锁定。
请注意,这getaddrinfo()
在 Linux 上也是线程安全的,因为只有当您的代码在多个线程运行时更改了语言环境或环境并且这样做本身被认为是线程不安全的时,它才会成为线程不安全的。因此,如果您无论如何都做了被禁止的事情,那么您只能使getaddrinfo()
线程不安全(好吧,这并不是真正被禁止的,但是您要自己承担风险,因为这样做不安全)。
还要注意,即使手册页没有说(一些 POSIX 手册页没有提到线程安全),POSIX 标准实际上要求:
3.407 线程安全
线程安全函数可以被多个线程安全地与对同一函数的其他调用或对任何其他线程安全函数的调用并发地调用。POSIX.1-2017 的系统接口卷中定义的每个函数都是线程安全的,除非另有明确说明。示例是任何“纯”函数,在访问静态存储时保持互斥锁锁定的函数,或线程之间共享的对象。
来源: http: //pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html