inet_ntoa与线程安全


之前在《Linux高性能服务器编程》中就有学习到 inet_ntoa 函数不可重入。

并且用程序验证了下

#include <arpa/inet.h>
#include <cstdio>

int main() {
  struct in_addr addr1, addr2;
  addr1.s_addr = inet_addr("192.180.2.1");
  addr2.s_addr = inet_addr("211.179.3.2");
  auto s1 = inet_ntoa(addr1);
  auto s2 = inet_ntoa(addr2);
  printf("%p %s\n", s1, s1);
  printf("%p %s\n", s2, s2);
  return 0;
}

输出:

0x7f34cabfa510 211.179.3.2
0x7f34cabfa510 211.179.3.2

所以易验证其不可重入性

然而今天 clang-tidy 给了我一个 warning

这似乎合情合理,因为其内部只有一个静态缓冲区,多个线程可能会重复覆盖,但真的如此吗?

(注:posix 标准规定 stdio 函数均为原子的,故 printf 不用同步,不会像 cout 一样混乱)

#include <arpa/inet.h>
#include <thread>

void print(const char *p) {
  struct in_addr addr;
  addr.s_addr = inet_addr(p);
  auto s = inet_ntoa(addr);
  printf("%p %s\n", s, s);
}

void work1() {
  print("192.180.2.1");
}

void work2() {
  print("211.179.3.2");
}

int main() {
  std::thread x1(work1);
  std::thread x2(work2);
  x1.join();
  x2.join();
  return 0;
}

输出:

0x7f7aaf10d6b0 192.180.2.1
0x7f7aae90c6b0 211.179.3.2

发现,貌似 inet_ntoa 是线程安全的?

小扒 gnu c library 源码看一看

于是发现了个 __thread 关键字。

__thread是GCC内置的线程局部存储设施。__thread 变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。

看来和 C++11 的 thread_local 差不多

所以可以暂且认为其是线程安全的


文章作者: caidd
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 caidd !
评论
  目录