背景
最近在实现一个日志库时,需要记录线程id,我采用C++ 11中的std::thread api获取,如下例子代码:
#include <thread>
#include <iostream>
int main()
{
std::thread::id tid = std::this_thread::get_id();
std::cout << tid << std::endl;
std::getchar();
}
输出
3676
上面是在windows上vs2015获取的tid值,看着是一个整型,很正常。
如果在linux g++ 环境下编译,输出如下:
139627072304960
一长串奇怪的数字,看到这个结果,我很诧异,在我的印象中,它应该跟windows下输出一样,是个正常的数字(没这么长)。为什么会有这样的印象:
我在linux调试程序时,通过top -Hp pid
命令看到的进程中线程的id(在我的理解中)是这样的:
top -Hp 18156
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18156 mjh 20 0 22996 1112 936 S 0.0 0.0 0:00.00 threadid
18157 mjh 20 0 22996 1112 936 S 0.0 0.0 0:00.00 threadid
如上top -Hp 命令,查看pid为18156的进程中线程资源占用情况,第一列PID理解成线程ID。这个值不像上面的程序那样返回一长串数字。
所以我认为g++ 下的std::thread::id的实现与我所理解的线程ID不一样。所以我写下面的一个测试代码(通过pthread_self获取thread id)
#include <iostream>
#include <thread>
int main()
{
std::cout<<std::this_thread::get_id()<<std::endl;
std::cout<<pthread_self()<<std::endl;
std::getchar();
}
在通过std::thread获取thread id的同时,也通过pthread_self()获取thread id,结果如下:
140586156734272
140586156734272
值一样,说明std::thread::get_id()获取的就是thread id。那么可以肯定,是我对thread id的理解有误了,那top -Hp 看到线程pid是什么?它跟thread id有什么不一样?
结论
通过一顿猛如虎的搜索,终于搞清楚了这些id的意义:
pthread_xxx系列API是POSIX中的标准,linux对pthread库的实现是通过内核级的轻量级进程来实现的。这些进程就跟普通的进程一样,有自己的pid可以被单独调度
那么就很显然了,top -Hp中的pid其实是内核中对应用户态的线程的进程的pid
线程id是有线程库所分配的,它是独立于进程空间的,就是不同的进程间,线程id可能会一样。线程id只在进程空间内有效。
g++中std::thread的实现也是基于pthread,产生线程ID只在进程空间内有效,通过 syscall(__NR_gettid) 获取线程的PID。
那么我们在实现诸如log这样的工具库时,应该记录线程的PID,通过这个PID可以直接配合一些进程资源监控工具(比如:top)来使用。