我正在使用getaddrinfo进行与IPv6相关的C项目。我的电脑上的“man getaddrinfo”(uname -a:3.5.0-23)仅表示它是“可重入的”。所以我猜它不是线程安全的。
在需要线程安全的情况下,如何处理它?我也检查了UNP,但似乎没有提供具体的答案。非常感谢。
getaddrinfo()
确实是线程安全的。这是RFC 3493 Section 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()
是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
getaddrinfo()是线程安全的。所有(或几乎所有)函数手册页都有关于线程安全性的信息。 Reentrant
意味着线程安全。