019.线程级接管eBPF内核志输出
函数bpf_get_current_pid_tgid得到的是进程id与线程id

前面的代码
存储日志是以pid为key
考虑到以后支持多线程
将存储日志的key改成进程id+线程id
具体操作,看视频
bpf_get_current_pid_tgid() 是 eBPF 里最常用、但也最容易被误解的 helper 之一。
我直接给你一个工程级、可上课用的解释。
一句话结论(标准答案)
bpf_get_current_pid_tgid()** 返回一个u64,
****高 32 位是tgid(进程 ID),
**低 32 位是pid(线程 ID / TID)。
精确定义(非常重要)
u64 id = bpf_get_current_pid_tgid();
位布局是:
63 ............... 32 | 31 ............... 0
tgid (PID) | pid (TID)
也就是:
tgid = id >> 32;
pid = (u32)id;
二、什么是 pid?什么是 tgid?(一定要讲清)
在 Linux 内核里:
| 名称 | 含义 |
|---|---|
| pid | 线程 ID(task_struct->pid) |
| tgid | 线程组 ID(task_struct->tgid) |
用户态常见的 getpid():
getpid() == tgid
用户态的 gettid():
gettid() == pid
三、典型正确用法(你现在课程里一定在用)
1️⃣ 只关心“哪个进程”
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32; // tgid
👉 99% tracing 工具用这个
2️⃣ 区分同一进程里的不同线程
u64 id = bpf_get_current_pid_tgid();
u32 tgid = id >> 32;
u32 tid = (u32)id;
👉 sched / lock / futex / pthread 场景必须这样
四、一个非常常见、也非常致命的坑 ❗
❌ 错误写法(你前面也问过)
u32 tid = pid_tgid >> 32;
u32 pid = (u32)pid_tgid;
👉 变量名和含义是反的
✅ 正确命名(强烈建议你在课里强调)
u64 pid_tgid = bpf_get_current_pid_tgid();
u32 tgid = pid_tgid >> 32; // 进程 ID
u32 pid = (u32)pid_tgid; // 线程 ID
五、为什么要把 pid / tgid 塞在一个 u64 里?
这是 eBPF helper 设计的工程取舍:
- 减少 helper 数量
- 一次读取,避免竞态
- map key 常用 u64
- 历史兼容(早期 BPF helper 设计)
六、和用户态看到的对照表(学生秒懂)
| 场景 | eBPF | 用户态 |
|---|---|---|
| 进程 ID | tgid |
getpid() |
| 线程 ID | pid |
gettid() |
| 单线程程序 | pid == tgid | 一样 |
| 多线程程序 | pid ≠ tgid | 不一样 |
七、一个真实例子(你可以直接贴)
假设某进程:
- 进程号:
1000 - 某线程号:
1003
那么:
u64 id = bpf_get_current_pid_tgid();
// id = 0x000003E8_000003EB
tgid = 1000
pid = 1003
八、课堂级总结(非常推荐)
**bpf_get_current_pid_tgid()
****返回的不是“一个 pid”,
**而是“一个进程 + 一个线程”。

浙公网安备 33010602011771号