如何处理getaddrinfo和线程安全?

时间:2013-09-04 00:40:18

标签: sockets ipv6 getaddrinfo

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

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

4 个答案:

答案 0 :(得分:11)

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

所必需的
  

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

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

答案 1 :(得分:1)

好吧,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()  │               │                    │
   └────────────────┴───────────────┴────────────────────┘

注意环境和语言环境:

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

答案 2 :(得分:0)

getaddrinfo()是POSIX标准的一部分,POSIX标准要求:

  

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

来源:http://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html

如果不是这样,则操作系统可能不会声称自己符合POSIX。

您可能听说过的操作系统正式符合POSIX:
AIX,BSD,IRIX,macOS,(开放式)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

答案 3 :(得分:0)

getaddrinfo()是线程安全的。所有(或几乎所有)功能手册页都有有关线程安全的信息。 Reentrant表示线程安全。