如何处理getaddrinfo和线程安全?

问题描述 投票:5回答:4

我正在使用getaddrinfo进行与IPv6相关的C项目。我的电脑上的“man getaddrinfo”(uname -a:3.5.0-23)仅表示它是“可重入的”。所以我猜它不是线程安全的。

在需要线程安全的情况下,如何处理它?我也检查了UNP,但似乎没有提供具体的答案。非常感谢。

sockets ipv6 getaddrinfo
4个回答
11
投票

getaddrinfo()确实是线程安全的。这是RFC 3493 Section 6.1要求的:

函数getaddrinfo()和freeaddrinfo()必须是线程安全的。

在某些平台上,gethostbyname()是线程安全的,但在其他平台上却不是。什么gethostbyname()不在所有平台上是重入的。如果你调用gethostbyname()然后在同一个线程中再次调用gethostbyname(),第一次调用的数据将被第二次调用的数据覆盖。这是因为gethostbyname()通常在内部使用静态缓冲区,这就是为什么你必须在再次调用gethostbyname()之前复制数据的原因。 getaddrinfo()不会遇到这个问题,因为它每次调用时都会分配一个新的addrinfo结构。


2
投票

好吧,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


0
投票

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


0
投票

getaddrinfo()是线程安全的。所有(或几乎所有)函数手册页都有关于线程安全性的信息。 Reentrant意味着线程安全。

© www.soinside.com 2019 - 2024. All rights reserved.