之前在《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 差不多
所以可以暂且认为其是线程安全的