GCC 警告 gettid() 系统调用包装器,glibc 2.30-8

GCC warns about gettid() syscall wrapper, with glibc 2.30-8

man page and SO post#1/SO post#2 都表明 gettid() 是在 glibc 2.30 中实现的。根据 ldd --version,我想我正在使用 GLIBC 2.30-8,但 gcc 仍然抱怨 - 警告:函数 'gettid 的隐式声明';您指的是 ‘getgid’ 吗? [-Wimplicit-function-declaration]。我可以忽略警告,程序运行正常。

我尝试与 gettid() 一起使用的 header 是 <sys/types.h>,遵循手册页。我错过了什么吗?

使用 header <sys/syscall.h> 调用 syscall(SYS_gettid) 不会触发来自 gcc 的警告。

注意:这太新了,没有某些条件不应该依赖它。而且,可能 永远不会 值得信赖。

见下文。


2019 年 2 月之前,联机帮助页是这样说的:

发件人:man gettid

Note: There is no glibc wrapper for this system call; see NOTES.

并且,来自注释:

Glibc does not provide a wrapper for this system call; call it using syscall(2).

有关详细信息,请参阅注释部分的其余部分。这是因为他们希望您使用其他 pthread_self 兼容的东西。

我个人不同意 glibc quirk/philosophy。

因为,有时需要使用real/linux tid值。


新方法是[截至 2019 年 2 月,据 Joseph 称]:

#define _GNU_SOURCE
#include <unistd.h>

获得gettid声明。

但是...

永远不会 [没有 #if/#ifdef] 因为 gettid 系统调用 已经被大约从 linux 2.4 开始,大约在 2004 年。

因此,添加包装函数花了glibc15年!?!? :-( IMO,太少,太晚了。

使用新方法时,它会破坏与那 15 年期间发布的所有发行版的向后兼容性。

所以,忽略这一点并继续使用 syscall 是可行的方法。这是保持 forward/backward 兼容性的最简单 方法。

我们可以创建包装器,但它更复杂[类似于]:

#if __GLIBC_PREREQ(2,30)
#define _GNU_SOURCE
#include <unistd.h>

#else

#include <sys/syscall.h>

pid_t
gettid(void)
{

    return syscall(SYS_gettid);
}
#endif

事实上,它比这更复杂,因为我们必须确保我们有 __GLIBC_PREREQ [and __GLIBC__ and __GLIBC_MINOR__] before[的定义=158=] 我们开始包括东西。

而且,要做到这一点是有问题的。所以,一个人可能会被迫总是做:

#define _GNU_SOURCE
#include <unistd.h>

然后,然后 添加 #if。或者,无论实际的神秘方式是什么[我无法亲自测试,因为我在使用旧方法的系统上]。

混乱,[IMO]不值得麻烦。


而且,情况更糟。

由于旧方法已经存在了很长时间,许多应用程序已经定义了自己的 gettid 包装函数。所以,新声明可能会与此冲突。

因此,开发人员无需执行任何操作即可重新编译他们的[以前]工作代码,并且构建现在会出错。

为了防止这种情况,unistd.h 应该 声明 gettid 如果用户在包含它之前放置了一些 #define (类似于_GNU_SOURCE) 喜欢:

#define _DECLARE_GETTID
#include <unistd.h>

而且,由于新方法打破了 15 年的兼容性,联机帮助页需要记录这一事实并解释旧方法。

因为,尝试编写跨平台代码、跨多个内核版本和多个 glibc 版本的开发人员需要了解这一点。


更新:

There's very good reason it was not added before - it was not a supported abstraction for application use.

这仍然没有授予他们打破向后兼容性的许可。

而且,必须为特殊应用程序(例如,那些与给定设备驱动程序密切合作的应用程序)合成缺失的功能

For a long time

15 岁以上 ...

glibc was entertaining the idea of possible thread models where the kernel tid would not be an invariant for the thread lifetime.

内核对pthread_t一无所知。它只知道 tid。这就是应用程序必须与内核通信的方式(例如 tgkill)。

内核的 模型中没有任何东西会改变 tid 中游,就像它不会改变 pid 中的进程一样执行到一半。

那是因为内核将 tid 当作 pid 来进行调度。每个进程和每个线程都有一个任务结构 [indexed/identified by pid/tid]。

否则,将需要对所有内核调度程序、task/thread 层次结构等进行大修。因此,glibc 不可能单独完成这项工作。而且,为了什么目的?

在创建线程的 clone 系统调用之后 [可以选择使用相同的地址 space],这在很大程度上是一个不可见的区别,线程在被调度时获得相同的权重 [基于关于调度程序和任务优先级。

这是内核方法的一大好处:tasks/threads 第一 class 公民[不同于 WinX]。

旁注: 我必须编写实时嵌入式 H/W H.264 视频编码器,并且必须处理 nptl [即linuxthreads(?)] 它导致了有关吞吐量和延迟的严重问题。幸运的是,nptl 在我们不得不发布之前出现了。区别是白天和黑夜。

It was only after relatively recent discussions that it was deemed ok.

内核[and/orPOSIX]定义了语义,而不是glibc。 glibc 开始遵循和实施,而不是命令。

而且,因为 glibc 人们顽固 [并且 令人讨厌 ],并且花了 15 年时间才决定 [ 显而易见 ], IMO,他们在这件事上失去了任何讨价还价的权利。

手册页中有关该函数的信息有误。而不是 #include <sys/types.h>,而是这样做:

#define _GNU_SOURCE
#include <unistd.h>

我向手册页邮件列表发送了一封电子邮件,要求更正此问题。